Initial code contribution
diff --git a/doc/placeholder b/doc/placeholder
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/doc/placeholder
diff --git a/htdocs/CustomizableContent/GuiEditor/AppConfig.json b/htdocs/CustomizableContent/GuiEditor/AppConfig.json
new file mode 100644
index 0000000..69a522d
--- /dev/null
+++ b/htdocs/CustomizableContent/GuiEditor/AppConfig.json
@@ -0,0 +1,5 @@
+{
+    "lastEditedApp": "CustomizableContent/CustomizableApp",
+    "lastEditedSetup": "EPTF_CLL_ProgressBar",
+    "confirmExit": false
+}
\ No newline at end of file
diff --git a/htdocs/CustomizableContent/GuiEditor/AppConfigSchema.json b/htdocs/CustomizableContent/GuiEditor/AppConfigSchema.json
new file mode 100644
index 0000000..37c933c
--- /dev/null
+++ b/htdocs/CustomizableContent/GuiEditor/AppConfigSchema.json
@@ -0,0 +1,22 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "GuiEditor",
+    "type": "object",
+    "additionalProperties": true,
+    "properties": {
+        "lastEditedApp": {
+            "description": "The last edited app.",
+            "type": "string"
+        },
+        "lastEditedSetup": {
+            "description": "The last edited setup.",
+            "type": "string"
+        },
+        "confirmExit": {
+            "description": "Whether we ask if the setup is to be saved when trying to exit GuiEditor.",
+            "type": "boolean",
+            "default": false
+        }
+    },
+    "required": ["lastEditedApp"]
+}
\ No newline at end of file
diff --git a/htdocs/CustomizableContent/MainConfig.json b/htdocs/CustomizableContent/MainConfig.json
new file mode 100644
index 0000000..b9f8329
--- /dev/null
+++ b/htdocs/CustomizableContent/MainConfig.json
@@ -0,0 +1,30 @@
+{
+    "availableApps": [
+        {
+            "directory": "WebApplications/CustomizableApp",
+            "name": "TitanSim",
+            "params": {
+                "customization": "CustomizableContent/CustomizableApp"
+            }
+        },
+        {
+            "directory": "WebApplications/GuiEditor",
+            "hidden": true
+        },
+        {
+            "directory": "WebApplications/RequestConsole",
+            "params": {
+                "customization": "CustomizableContent/CustomizableApp"
+            },
+            "hidden": true
+        },
+        {
+            "directory": "WebApplications/WebpageFrame",
+            "params": {
+                "location": "http://ttcn.ericsson.se/TitanSim/Help/"
+            },
+            "name": "Help"
+        }
+    ],
+    "defaultApp": "TitanSim"
+}
\ No newline at end of file
diff --git a/htdocs/CustomizableContent/RequestConsole/AppConfig.json b/htdocs/CustomizableContent/RequestConsole/AppConfig.json
new file mode 100644
index 0000000..ea8d14c
--- /dev/null
+++ b/htdocs/CustomizableContent/RequestConsole/AppConfig.json
@@ -0,0 +1,6 @@
+{
+    "lastEditedApp": "CustomizableContent/RequestConsole",
+    "confirmExit": false,
+    "lastEditedSetup": "DsRestAPI_Console_Default",
+    "appForListingSetups": "CustomizableContent/CustomizableApp"
+}
\ No newline at end of file
diff --git a/htdocs/CustomizableContent/RequestConsole/AppConfigSchema.json b/htdocs/CustomizableContent/RequestConsole/AppConfigSchema.json
new file mode 100644
index 0000000..6b88b24
--- /dev/null
+++ b/htdocs/CustomizableContent/RequestConsole/AppConfigSchema.json
@@ -0,0 +1,26 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "RequestConsole",
+    "type": "object",
+    "additionalProperties": true,
+    "properties": {
+        "lastEditedApp": {
+            "description": "The last edited app.",
+            "type": "string"
+        },
+        "lastEditedSetup": {
+            "description": "The last edited setup.",
+            "type": "string"
+        },
+        "appForListingSetups": {
+            "description": "App path used to list setups to be loaded.",
+            "type": "string"
+        },
+        "confirmExit": {
+            "description": "Whether we ask if the setup is to be saved when trying to exit RequestConsole.",
+            "type": "boolean",
+            "default": false
+        }
+    },
+    "required": ["lastEditedApp"]
+}
\ No newline at end of file
diff --git a/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Desktop.json b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Desktop.json
new file mode 100644
index 0000000..07392e9
--- /dev/null
+++ b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Desktop.json
@@ -0,0 +1,19 @@
+{
+    "ViewmodelEditors": [],
+    "ViewEditors": [],
+    "Imports": [],
+    "HtmlEditor": {
+        "pos": {
+            "top": 0,
+            "left": 970
+        },
+        "visible": true
+    },
+    "RequestEditor": {
+        "openRequests": [
+            [
+                0
+            ]
+        ]
+    }
+}
\ No newline at end of file
diff --git a/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Imports.json b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Imports.json
new file mode 100644
index 0000000..0637a08
--- /dev/null
+++ b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Imports.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Request.json b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Request.json
new file mode 100644
index 0000000..b0833a4
--- /dev/null
+++ b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Request.json
@@ -0,0 +1,33 @@
+[
+    {
+        "getData": {
+            "source": "ExecCtrl",
+            "element": "EntityGroups",
+            "children": [
+                {
+                    "getData": {
+                        "source": "ExecCtrl",
+                        "element": "Scenarios",
+                        "params": [
+                            {
+                                "paramName": "EntityGroup",
+                                "paramValue": "%Parent0%"
+                            }
+                        ]
+                    }
+                }
+            ],
+            "selection": [
+                0
+            ]
+        }
+    },
+    {
+        "setData": {
+            "source": "ExecCtrl",
+            "element": "Start",
+            "content": "1",
+            "tp": 1
+        }
+    }
+]
\ No newline at end of file
diff --git a/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Setup.css b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Setup.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Setup.css
diff --git a/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Setup.html b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Setup.html
new file mode 100644
index 0000000..43ec6f0
--- /dev/null
+++ b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/Setup.html
@@ -0,0 +1 @@
+<div id="div_id"></div>
\ No newline at end of file
diff --git a/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/ViewInstances.json b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/ViewInstances.json
new file mode 100644
index 0000000..0637a08
--- /dev/null
+++ b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/ViewInstances.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/ViewModelInstances.json b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/ViewModelInstances.json
new file mode 100644
index 0000000..0637a08
--- /dev/null
+++ b/htdocs/CustomizableContent/RequestConsole/Setups/DsRestAPI_Console_Default/ViewModelInstances.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/htdocs/Libs/AJV/ajv.min.js b/htdocs/Libs/AJV/ajv.min.js
new file mode 100644
index 0000000..6dd7203
--- /dev/null
+++ b/htdocs/Libs/AJV/ajv.min.js
@@ -0,0 +1,6 @@
+/* Ajv JSON-schema validator */
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var r;r="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,r.Ajv=e()}}(function(){var define,module,exports;return function e(r,t,a){function s(i,n){if(!t[i]){if(!r[i]){var l="function"==typeof require&&require;if(!n&&l)return l(i,!0);if(o)return o(i,!0);var h=new Error("Cannot find module '"+i+"'");throw h.code="MODULE_NOT_FOUND",h}var u=t[i]={exports:{}};r[i][0].call(u.exports,function(e){var t=r[i][1][e];return s(t?t:e)},u,u.exports,e,r,t,a)}return t[i].exports}for(var o="function"==typeof require&&require,i=0;a.length>i;i++)s(a[i]);return s}({1:[function(e,r,t){(function(e){!function(a){function s(e){throw new RangeError(q[e])}function o(e,r){for(var t=e.length,a=[];t--;)a[t]=r(e[t]);return a}function i(e,r){var t=e.split("@"),a="";t.length>1&&(a=t[0]+"@",e=t[1]),e=e.replace(A,".");var s=e.split("."),i=o(s,r).join(".");return a+i}function n(e){for(var r,t,a=[],s=0,o=e.length;o>s;)r=e.charCodeAt(s++),r>=55296&&56319>=r&&o>s?(t=e.charCodeAt(s++),56320==(64512&t)?a.push(((1023&r)<<10)+(1023&t)+65536):(a.push(r),s--)):a.push(r);return a}function l(e){return o(e,function(e){var r="";return e>65535&&(e-=65536,r+=D(e>>>10&1023|55296),e=56320|1023&e),r+=D(e)}).join("")}function h(e){return 10>e-48?e-22:26>e-65?e-65:26>e-97?e-97:j}function u(e,r){return e+22+75*(26>e)-((0!=r)<<5)}function c(e,r,t){var a=0;for(e=t?C(e/S):e>>1,e+=C(e/r);e>L*x>>1;a+=j)e=C(e/L);return C(a+(L+1)*e/(e+R))}function f(e){var r,t,a,o,i,n,u,f,d,p,m=[],v=e.length,y=0,P=O,g=w;for(t=e.lastIndexOf(_),0>t&&(t=0),a=0;t>a;++a)e.charCodeAt(a)>=128&&s("not-basic"),m.push(e.charCodeAt(a));for(o=t>0?t+1:0;v>o;){for(i=y,n=1,u=j;o>=v&&s("invalid-input"),f=h(e.charCodeAt(o++)),(f>=j||f>C((E-y)/n))&&s("overflow"),y+=f*n,d=g>=u?$:u>=g+x?x:u-g,!(d>f);u+=j)p=j-d,n>C(E/p)&&s("overflow"),n*=p;r=m.length+1,g=c(y-i,r,0==i),C(y/r)>E-P&&s("overflow"),P+=C(y/r),y%=r,m.splice(y++,0,P)}return l(m)}function d(e){var r,t,a,o,i,l,h,f,d,p,m,v,y,P,g,b=[];for(e=n(e),v=e.length,r=O,t=0,i=w,l=0;v>l;++l)m=e[l],128>m&&b.push(D(m));for(a=o=b.length,o&&b.push(_);v>a;){for(h=E,l=0;v>l;++l)m=e[l],m>=r&&h>m&&(h=m);for(y=a+1,h-r>C((E-t)/y)&&s("overflow"),t+=(h-r)*y,r=h,l=0;v>l;++l)if(m=e[l],r>m&&++t>E&&s("overflow"),m==r){for(f=t,d=j;p=i>=d?$:d>=i+x?x:d-i,!(p>f);d+=j)g=f-p,P=j-p,b.push(D(u(p+g%P,0))),f=C(g/P);b.push(D(u(f,0))),i=c(t,y,a==o),t=0,++a}++t,++r}return b.join("")}function p(e){return i(e,function(e){return k.test(e)?f(e.slice(4).toLowerCase()):e})}function m(e){return i(e,function(e){return I.test(e)?"xn--"+d(e):e})}var v="object"==typeof t&&t&&!t.nodeType&&t,y="object"==typeof r&&r&&!r.nodeType&&r,P="object"==typeof e&&e;(P.global===P||P.window===P||P.self===P)&&(a=P);var g,b,E=2147483647,j=36,$=1,x=26,R=38,S=700,w=72,O=128,_="-",k=/^xn--/,I=/[^\x20-\x7E]/,A=/[\x2E\u3002\uFF0E\uFF61]/g,q={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},L=j-$,C=Math.floor,D=String.fromCharCode;if(g={version:"1.3.2",ucs2:{decode:n,encode:l},decode:f,encode:d,toASCII:m,toUnicode:p},"function"==typeof define&&"object"==typeof define.amd&&define.amd)define("punycode",function(){return g});else if(v&&y)if(r.exports==v)y.exports=g;else for(b in g)g.hasOwnProperty(b)&&(v[b]=g[b]);else a.punycode=g}(this)}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],2:[function(e,r,t){"use strict";function a(e,r){return Object.prototype.hasOwnProperty.call(e,r)}r.exports=function(e,r,t,o){r=r||"&",t=t||"=";var i={};if("string"!=typeof e||0===e.length)return i;var n=/\+/g;e=e.split(r);var l=1e3;o&&"number"==typeof o.maxKeys&&(l=o.maxKeys);var h=e.length;l>0&&h>l&&(h=l);for(var u=0;h>u;++u){var c,f,d,p,m=e[u].replace(n,"%20"),v=m.indexOf(t);v>=0?(c=m.substr(0,v),f=m.substr(v+1)):(c=m,f=""),d=decodeURIComponent(c),p=decodeURIComponent(f),a(i,d)?s(i[d])?i[d].push(p):i[d]=[i[d],p]:i[d]=p}return i};var s=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)}},{}],3:[function(e,r,t){"use strict";function a(e,r){if(e.map)return e.map(r);for(var t=[],a=0;e.length>a;a++)t.push(r(e[a],a));return t}var s=function(e){switch(typeof e){case"string":return e;case"boolean":return e?"true":"false";case"number":return isFinite(e)?e:"";default:return""}};r.exports=function(e,r,t,n){return r=r||"&",t=t||"=",null===e&&(e=void 0),"object"==typeof e?a(i(e),function(i){var n=encodeURIComponent(s(i))+t;return o(e[i])?a(e[i],function(e){return n+encodeURIComponent(s(e))}).join(r):n+encodeURIComponent(s(e[i]))}).join(r):n?encodeURIComponent(s(n))+t+encodeURIComponent(s(e)):""};var o=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},i=Object.keys||function(e){var r=[];for(var t in e)Object.prototype.hasOwnProperty.call(e,t)&&r.push(t);return r}},{}],4:[function(e,r,t){"use strict";t.decode=t.parse=e("./decode"),t.encode=t.stringify=e("./encode")},{"./decode":2,"./encode":3}],5:[function(e,r,t){"use strict";function a(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}function s(e,r,t){if(e&&h.isObject(e)&&e instanceof a)return e;var s=new a;return s.parse(e,r,t),s}function o(e){return h.isString(e)&&(e=s(e)),e instanceof a?e.format():a.prototype.format.call(e)}function i(e,r){return s(e,!1,!0).resolve(r)}function n(e,r){return e?s(e,!1,!0).resolveObject(r):r}var l=e("punycode"),h=e("./util");t.parse=s,t.resolve=i,t.resolveObject=n,t.format=o,t.Url=a;var u=/^([a-z0-9.+-]+:)/i,c=/:[0-9]*$/,f=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,d=["<",">",'"',"`"," ","\r","\n","	"],p=["{","}","|","\\","^","`"].concat(d),m=["'"].concat(p),v=["%","/","?",";","#"].concat(m),y=["/","?","#"],P=255,g=/^[+a-z0-9A-Z_-]{0,63}$/,b=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,E={javascript:!0,"javascript:":!0},j={javascript:!0,"javascript:":!0},$={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},x=e("querystring");a.prototype.parse=function(e,r,t){if(!h.isString(e))throw new TypeError("Parameter 'url' must be a string, not "+typeof e);var a=e.indexOf("?"),s=-1!==a&&a<e.indexOf("#")?"?":"#",o=e.split(s),i=/\\/g;o[0]=o[0].replace(i,"/"),e=o.join(s);var n=e;if(n=n.trim(),!t&&1===e.split("#").length){var c=f.exec(n);if(c)return this.path=n,this.href=n,this.pathname=c[1],c[2]?(this.search=c[2],this.query=r?x.parse(this.search.substr(1)):this.search.substr(1)):r&&(this.search="",this.query={}),this}var d=u.exec(n);if(d){d=d[0];var p=d.toLowerCase();this.protocol=p,n=n.substr(d.length)}if(t||d||n.match(/^\/\/[^@\/]+@[^@\/]+/)){var R="//"===n.substr(0,2);!R||d&&j[d]||(n=n.substr(2),this.slashes=!0)}if(!j[d]&&(R||d&&!$[d])){for(var S=-1,w=0;y.length>w;w++){var O=n.indexOf(y[w]);-1!==O&&(-1===S||S>O)&&(S=O)}var _,k;k=-1===S?n.lastIndexOf("@"):n.lastIndexOf("@",S),-1!==k&&(_=n.slice(0,k),n=n.slice(k+1),this.auth=decodeURIComponent(_)),S=-1;for(var w=0;v.length>w;w++){var O=n.indexOf(v[w]);-1!==O&&(-1===S||S>O)&&(S=O)}-1===S&&(S=n.length),this.host=n.slice(0,S),n=n.slice(S),this.parseHost(),this.hostname=this.hostname||"";var I="["===this.hostname[0]&&"]"===this.hostname[this.hostname.length-1];if(!I)for(var A=this.hostname.split(/\./),w=0,q=A.length;q>w;w++){var L=A[w];if(L&&!L.match(g)){for(var C="",D=0,U=L.length;U>D;D++)C+=L.charCodeAt(D)>127?"x":L[D];if(!C.match(g)){var z=A.slice(0,w),M=A.slice(w+1),T=L.match(b);T&&(z.push(T[1]),M.unshift(T[2])),M.length&&(n="/"+M.join(".")+n),this.hostname=z.join(".");break}}}this.hostname=this.hostname.length>P?"":this.hostname.toLowerCase(),I||(this.hostname=l.toASCII(this.hostname));var Q=this.port?":"+this.port:"",H=this.hostname||"";this.host=H+Q,this.href+=this.host,I&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==n[0]&&(n="/"+n))}if(!E[p])for(var w=0,q=m.length;q>w;w++){var N=m[w];if(-1!==n.indexOf(N)){var V=encodeURIComponent(N);V===N&&(V=escape(N)),n=n.split(N).join(V)}}var F=n.indexOf("#");-1!==F&&(this.hash=n.substr(F),n=n.slice(0,F));var G=n.indexOf("?");if(-1!==G?(this.search=n.substr(G),this.query=n.substr(G+1),r&&(this.query=x.parse(this.query)),n=n.slice(0,G)):r&&(this.search="",this.query={}),n&&(this.pathname=n),$[p]&&this.hostname&&!this.pathname&&(this.pathname="/"),this.pathname||this.search){var Q=this.pathname||"",K=this.search||"";this.path=Q+K}return this.href=this.format(),this},a.prototype.format=function(){var e=this.auth||"";e&&(e=encodeURIComponent(e),e=e.replace(/%3A/i,":"),e+="@");var r=this.protocol||"",t=this.pathname||"",a=this.hash||"",s=!1,o="";this.host?s=e+this.host:this.hostname&&(s=e+(-1===this.hostname.indexOf(":")?this.hostname:"["+this.hostname+"]"),this.port&&(s+=":"+this.port)),this.query&&h.isObject(this.query)&&Object.keys(this.query).length&&(o=x.stringify(this.query));var i=this.search||o&&"?"+o||"";return r&&":"!==r.substr(-1)&&(r+=":"),this.slashes||(!r||$[r])&&s!==!1?(s="//"+(s||""),t&&"/"!==t.charAt(0)&&(t="/"+t)):s||(s=""),a&&"#"!==a.charAt(0)&&(a="#"+a),i&&"?"!==i.charAt(0)&&(i="?"+i),t=t.replace(/[?#]/g,function(e){return encodeURIComponent(e)}),i=i.replace("#","%23"),r+s+t+i+a},a.prototype.resolve=function(e){return this.resolveObject(s(e,!1,!0)).format()},a.prototype.resolveObject=function(e){if(h.isString(e)){var r=new a;r.parse(e,!1,!0),e=r}for(var t=new a,s=Object.keys(this),o=0;s.length>o;o++){var i=s[o];t[i]=this[i]}if(t.hash=e.hash,""===e.href)return t.href=t.format(),t;if(e.slashes&&!e.protocol){for(var n=Object.keys(e),l=0;n.length>l;l++){var u=n[l];"protocol"!==u&&(t[u]=e[u])}return $[t.protocol]&&t.hostname&&!t.pathname&&(t.path=t.pathname="/"),t.href=t.format(),t}if(e.protocol&&e.protocol!==t.protocol){if(!$[e.protocol]){for(var c=Object.keys(e),f=0;c.length>f;f++){var d=c[f];t[d]=e[d]}return t.href=t.format(),t}if(t.protocol=e.protocol,e.host||j[e.protocol])t.pathname=e.pathname;else{for(var p=(e.pathname||"").split("/");p.length&&!(e.host=p.shift()););e.host||(e.host=""),e.hostname||(e.hostname=""),""!==p[0]&&p.unshift(""),2>p.length&&p.unshift(""),t.pathname=p.join("/")}if(t.search=e.search,t.query=e.query,t.host=e.host||"",t.auth=e.auth,t.hostname=e.hostname||e.host,t.port=e.port,t.pathname||t.search){var m=t.pathname||"",v=t.search||"";t.path=m+v}return t.slashes=t.slashes||e.slashes,t.href=t.format(),t}var y=t.pathname&&"/"===t.pathname.charAt(0),P=e.host||e.pathname&&"/"===e.pathname.charAt(0),g=P||y||t.host&&e.pathname,b=g,E=t.pathname&&t.pathname.split("/")||[],p=e.pathname&&e.pathname.split("/")||[],x=t.protocol&&!$[t.protocol];if(x&&(t.hostname="",t.port=null,t.host&&(""===E[0]?E[0]=t.host:E.unshift(t.host)),t.host="",e.protocol&&(e.hostname=null,e.port=null,e.host&&(""===p[0]?p[0]=e.host:p.unshift(e.host)),e.host=null),g=g&&(""===p[0]||""===E[0])),P)t.host=e.host||""===e.host?e.host:t.host,t.hostname=e.hostname||""===e.hostname?e.hostname:t.hostname,t.search=e.search,t.query=e.query,E=p;else if(p.length)E||(E=[]),E.pop(),E=E.concat(p),t.search=e.search,t.query=e.query;else if(!h.isNullOrUndefined(e.search)){if(x){t.hostname=t.host=E.shift();var R=t.host&&t.host.indexOf("@")>0?t.host.split("@"):!1;R&&(t.auth=R.shift(),t.host=t.hostname=R.shift())}return t.search=e.search,t.query=e.query,h.isNull(t.pathname)&&h.isNull(t.search)||(t.path=(t.pathname?t.pathname:"")+(t.search?t.search:"")),t.href=t.format(),t}if(!E.length)return t.pathname=null,t.path=t.search?"/"+t.search:null,t.href=t.format(),t;for(var S=E.slice(-1)[0],w=(t.host||e.host||E.length>1)&&("."===S||".."===S)||""===S,O=0,_=E.length;_>=0;_--)S=E[_],"."===S?E.splice(_,1):".."===S?(E.splice(_,1),O++):O&&(E.splice(_,1),O--);if(!g&&!b)for(;O--;O)E.unshift("..");!g||""===E[0]||E[0]&&"/"===E[0].charAt(0)||E.unshift(""),w&&"/"!==E.join("/").substr(-1)&&E.push("");var k=""===E[0]||E[0]&&"/"===E[0].charAt(0);if(x){t.hostname=t.host=k?"":E.length?E.shift():"";var R=t.host&&t.host.indexOf("@")>0?t.host.split("@"):!1;R&&(t.auth=R.shift(),t.host=t.hostname=R.shift())}return g=g||t.host&&E.length,g&&!k&&E.unshift(""),E.length?t.pathname=E.join("/"):(t.pathname=null,t.path=null),h.isNull(t.pathname)&&h.isNull(t.search)||(t.path=(t.pathname?t.pathname:"")+(t.search?t.search:"")),t.auth=e.auth||t.auth,t.slashes=t.slashes||e.slashes,t.href=t.format(),t},a.prototype.parseHost=function(){var e=this.host,r=c.exec(e);r&&(r=r[0],":"!==r&&(this.port=r.substr(1)),e=e.substr(0,e.length-r.length)),e&&(this.hostname=e)}},{"./util":6,punycode:1,querystring:4}],6:[function(e,r,t){"use strict";r.exports={isString:function(e){return"string"==typeof e},isObject:function(e){return"object"==typeof e&&null!==e},isNull:function(e){return null===e},isNullOrUndefined:function(e){return null==e}}},{}],7:[function(e,r,t){"use strict";r.exports=function(e,r){function t(e,r,a){function o(a){function o(a,o){if(a)r(a);else{if(!s._refs[i]&&!s._schemas[i])try{s.addSchema(o,i)}catch(n){return void r(n)}t(e,r)}}var i=a.missingSchema;if(s._refs[i]||s._schemas[i])return r(new Error("Schema "+i+" is loaded but"+a.missingRef+"cannot be resolved"));var n=s._loadingSchemas[i];n?"function"==typeof n?s._loadingSchemas[i]=[n,o]:n[n.length]=o:(s._loadingSchemas[i]=o,s.opts.loadSchema(i,function(e,r){var t=s._loadingSchemas[i];if(delete s._loadingSchemas[i],"function"==typeof t)t(e,r);else for(var a=0;t.length>a;a++)t[a](e,r)}))}function i(e,t){a?setTimeout(function(){r(e,t)}):r(e,t)}var n;try{n=s.compile(e)}catch(l){return void(l.missingSchema?o(l):i(l))}i(null,n)}var a,s=this;try{a=this._addSchema(e)}catch(o){return void setTimeout(function(){r(o)})}if(a.validate)setTimeout(function(){r(null,a.validate)});else{if("function"!=typeof this.opts.loadSchema)throw new Error("options.loadSchema should be a function");t(e,r,!0)}}},{}],8:[function(e,r,t){"use strict";var a=r.exports=function(){this._cache={}};a.prototype.put=function(e,r){this._cache[e]=r},a.prototype.get=function(e){return this._cache[e]},a.prototype.del=function(e){delete this._cache[e]}},{}],9:[function(e,r,t){"use strict";r.exports={$ref:e("../dotjs/ref"),allOf:e("../dotjs/allOf"),anyOf:e("../dotjs/anyOf"),dependencies:e("../dotjs/dependencies"),"enum":e("../dotjs/enum"),format:e("../dotjs/format"),items:e("../dotjs/items"),maximum:e("../dotjs/_limit"),minimum:e("../dotjs/_limit"),maxItems:e("../dotjs/_limitItems"),minItems:e("../dotjs/_limitItems"),maxLength:e("../dotjs/_limitLength"),minLength:e("../dotjs/_limitLength"),maxProperties:e("../dotjs/_limitProperties"),minProperties:e("../dotjs/_limitProperties"),multipleOf:e("../dotjs/multipleOf"),not:e("../dotjs/not"),oneOf:e("../dotjs/oneOf"),pattern:e("../dotjs/pattern"),properties:e("../dotjs/properties"),required:e("../dotjs/required"),uniqueItems:e("../dotjs/uniqueItems"),validate:e("../dotjs/validate")}},{"../dotjs/_limit":18,"../dotjs/_limitItems":19,"../dotjs/_limitLength":20,"../dotjs/_limitProperties":21,"../dotjs/allOf":22,"../dotjs/anyOf":23,"../dotjs/dependencies":25,"../dotjs/enum":26,"../dotjs/format":27,"../dotjs/items":28,"../dotjs/multipleOf":29,"../dotjs/not":30,"../dotjs/oneOf":31,"../dotjs/pattern":32,"../dotjs/properties":33,"../dotjs/ref":34,"../dotjs/required":35,"../dotjs/uniqueItems":37,"../dotjs/validate":38}],10:[function(e,r,t){"use strict";r.exports=function a(e,r){if(e===r)return!0;var t,s=Array.isArray(e),o=Array.isArray(r);if(s&&o){if(e.length!=r.length)return!1;for(t=0;e.length>t;t++)if(!a(e[t],r[t]))return!1;return!0}if(s!=o)return!1;if(e&&r&&"object"==typeof e&&"object"==typeof r){var i=Object.keys(e);if(i.length!==Object.keys(r).length)return!1;for(t=0;i.length>t;t++)if(void 0===r[i[t]])return!1;for(t=0;i.length>t;t++)if(!a(e[i[t]],r[i[t]]))return!1;return!0}return!1}},{}],11:[function(e,r,t){"use strict";function a(e){e="full"==e?"full":"fast";var r=d.copy(a[e]);for(var t in a.compare)r[t]={validate:r[t],compare:a.compare[t]};return r}function s(e){var r=e.match(p);if(!r)return!1;var t=+r[1],a=+r[2];return t>=1&&12>=t&&a>=1&&m[t]>=a}function o(e,r){var t=e.match(v);if(!t)return!1;var a=t[1],s=t[2],o=t[3],i=t[5];return 23>=a&&59>=s&&59>=o&&(!r||i)}function i(e){var r=e.split(j);return s(r[0])&&o(r[1],!0)}function n(e){return 255>=e.length&&y.test(e)}function l(e){return $.test(e)&&P.test(e)}function h(e){try{return new RegExp(e),!0}catch(r){return!1}}function u(e,r){return e&&r?e>r?1:r>e?-1:e===r?0:void 0:void 0}function c(e,r){return e&&r&&(e=e.match(v),r=r.match(v),e&&r)?(e=e[1]+e[2]+e[3]+(e[4]||""),r=r[1]+r[2]+r[3]+(r[4]||""),e>r?1:r>e?-1:e===r?0:void 0):void 0}function f(e,r){if(e&&r){e=e.split(j),r=r.split(j);var t=u(e[0],r[0]);if(void 0!==t)return t||c(e[1],r[1])}}var d=e("./util"),p=/^\d\d\d\d-(\d\d)-(\d\d)$/,m=[0,31,29,31,30,31,30,31,31,30,31,30,31],v=/^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d:\d\d)?$/i,y=/^[a-z](?:(?:[-0-9a-z]{0,61})?[0-9a-z])?(\.[a-z](?:(?:[-0-9a-z]{0,61})?[0-9a-z])?)*$/i,P=/^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@\/?]|%[0-9a-f]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'()*+,;=:@\/?]|%[0-9a-f]{2})*)?$/i,g=/^(?:urn\:uuid\:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i,b=/^(?:\/(?:[^~\/]|~0|~1)+)*(?:\/)?$|^\#(?:\/(?:[a-z0-9_\-\.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)+)*(?:\/)?$/i,E=/^(?:0|[1-9][0-9]*)(?:\#|(?:\/(?:[^~\/]|~0|~1)+)*(?:\/)?)$/;r.exports=a,a.fast={date:/^\d\d\d\d-[0-1]\d-[0-3]\d$/,time:/^[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:z|[+-]\d\d:\d\d)?$/i,"date-time":/^\d\d\d\d-[0-1]\d-[0-3]\d[t\s][0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:z|[+-]\d\d:\d\d)$/i,uri:/^(?:[a-z][a-z0-9+-.]*)?(?:\:|\/)\/?[^\s]*$/i,email:/^[a-z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i,hostname:y,ipv4:/^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,ipv6:/^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i,regex:h,uuid:g,"json-pointer":b,"relative-json-pointer":E},a.full={date:s,time:o,"date-time":i,uri:l,email:/^[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&''*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i,hostname:n,ipv4:/^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,ipv6:/^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i,regex:h,uuid:g,"json-pointer":b,"relative-json-pointer":E},a.compare={date:u,time:c,"date-time":f};var j=/t|\s/i,$=/\/|\:/},{"./util":16}],12:[function(require,module,exports){"use strict";function compile(schema,root,localRefs,baseId){function localCompile(_schema,_root,localRefs,baseId){var isRoot=!_root||_root&&_root.schema==_schema;if(_root.schema!=root.schema)return compile.call(self,_schema,_root,localRefs,baseId);var validateCode=validateGenerator({isTop:!0,schema:_schema,isRoot:isRoot,baseId:baseId,root:_root,schemaPath:"",errSchemaPath:"#",errorPath:'""',RULES:RULES,validate:validateGenerator,util:util,resolve:resolve,resolveRef:resolveRef,usePattern:usePattern,useDefault:useDefault,useCustomRule:useCustomRule,opts:self.opts,formats:formats,self:self});if(validateCode=vars(refVal,refValCode)+vars(patterns,patternCode)+vars(defaults,defaultCode)+vars(customRules,customRuleCode)+validateCode,self.opts.beautify){var opts=self.opts.beautify===!0?{indent_size:2}:self.opts.beautify;beautify?validateCode=beautify(validateCode,opts):console.error('"npm install js-beautify" to use beautify option')}var validate;try{eval(validateCode),refVal[0]=validate}catch(e){throw console.log("Error compiling schema, function code:",validateCode),e}return validate.schema=_schema,validate.errors=null,validate.refs=refs,validate.refVal=refVal,validate.root=isRoot?validate:_root,validate}function resolveRef(e,r,t){r=resolve.url(e,r);var a,s,o=refs[r];if(void 0!==o)return a=refVal[o],s="refVal["+o+"]",resolvedRef(a,s);if(!t){var i=root.refs[r];if(void 0!==i)return a=root.refVal[i],s=addLocalRef(r,a),resolvedRef(a,s)}s=addLocalRef(r);var n=resolve.call(self,localCompile,root,r);if(!n){var l=localRefs&&localRefs[r];l&&(n=resolve.inlineRef(l,self.opts.inlineRefs)?l:compile.call(self,l,root,localRefs,e))}return n?(replaceLocalRef(r,n),resolvedRef(n,s)):void 0}function addLocalRef(e,r){var t=refVal.length;return refVal[t]=r,refs[e]=t,"refVal"+t}function replaceLocalRef(e,r){var t=refs[e];refVal[t]=r}function resolvedRef(e,r){return"object"==typeof e?{schema:e,code:r}:r}function usePattern(e){var r=patternsHash[e];return void 0===r&&(r=patternsHash[e]=patterns.length,patterns[r]=e),"pattern"+r}function useDefault(e){switch(typeof e){case"boolean":case"number":return""+e;case"string":return util.toQuotedString(e);case"object":if(null===e)return"null";var r=stableStringify(e),t=defaultsHash[r];return void 0===t&&(t=defaultsHash[r]=defaults.length,defaults[t]=e),"default"+t}}function useCustomRule(e,r,t,a){var s,o=e.definition.compile,i=e.definition.inline,n=e.definition.macro;o?s=o.call(self,r,t):n?(s=n.call(self,r,t),self.opts.validateSchema!==!1&&self.validateSchema(s,!0)):s=i?i.call(self,a,e.keyword,r,t):e.definition.validate;var l=customRules.length;return customRules[l]=s,{code:"customRule"+l,validate:s}}var self=this,refVal=[void 0],refs={},patterns=[],patternsHash={},defaults=[],defaultsHash={},customRules=[],customRulesHash={};root=root||{schema:schema,refVal:refVal,refs:refs};var formats=this._formats,RULES=this.RULES;return localCompile(schema,root,localRefs,baseId)}function patternCode(e,r){return"var pattern"+e+" = new RegExp("+util.toQuotedString(r[e])+");"}function defaultCode(e){return"var default"+e+" = defaults["+e+"];"}function refValCode(e,r){return r[e]?"var refVal"+e+" = refVal["+e+"];":""}function customRuleCode(e){return"var customRule"+e+" = customRules["+e+"];"}function vars(e,r){if(!e.length)return"";for(var t="",a=0;e.length>a;a++)t+=r(a,e);return t}var resolve=require("./resolve"),util=require("./util"),equal=require("./equal"),stableStringify=require("json-stable-stringify"),beautify=function(){try{return require("js-beautify").js_beautify}catch(e){}}(),validateGenerator=require("../dotjs/validate");module.exports=compile;var ucs2length=util.ucs2length},{"../dotjs/validate":38,"./equal":10,"./resolve":13,"./util":16,"json-stable-stringify":43}],13:[function(e,r,t){"use strict";function a(e,r,t){var o=this._refs[t];if("string"==typeof o){if(!this._refs[o])return a.call(this,e,r,o);o=this._refs[o]}if(o=o||this._schemas[t],o instanceof P)return n(o.schema,this.opts.inlineRefs)?o.schema:o.validate||this._compile(o);var i,l,h,u=s.call(this,r,t);return u&&(i=u.schema,r=u.root,h=u.baseId),i instanceof P?l=i.validate||e.call(this,i.schema,r,void 0,h):i&&(l=n(i,this.opts.inlineRefs)?i:e.call(this,i,r,void 0,h)),l}function s(e,r){var t=m.parse(r,!1,!0),a=c(t),s=u(e.schema.id);if(a!==s){var n=f(a),l=this._refs[n];if("string"==typeof l)return o.call(this,e,l,t);if(l instanceof P)l.validate||this._compile(l),e=l;else if(l=this._schemas[n],l instanceof P){if(l.validate||this._compile(l),n==f(r))return{schema:l,root:e,baseId:s};e=l}if(!e.schema)return;s=u(e.schema.id)}return i.call(this,t,s,e.schema,e)}function o(e,r,t){var a=s.call(this,e,r);if(a){var o=a.schema,n=a.baseId;return e=a.root,o.id&&(n=d(n,o.id)),i.call(this,t,n,o,e)}}function i(e,r,t,a){if(e.hash=e.hash||"","#/"==e.hash.slice(0,2)){for(var o=e.hash.split("/"),i=1;o.length>i;i++){var n=o[i];if(n){if(n=y.unescapeFragment(n),t=t[n],!t)break;if(t.id&&!g[n]&&(r=d(r,t.id)),t.$ref){var l=d(r,t.$ref),h=s.call(this,a,l);h&&(t=h.schema,a=h.root,r=h.baseId)}}}return t&&t!=a.schema?{schema:t,root:a,baseId:r}:void 0}}function n(e,r){return void 0===r?l(e):r?h(e)<=r:void 0}function l(e){var r;if(Array.isArray(e)){for(var t=0;e.length>t;t++)if(r=e[t],"object"==typeof r&&!l(r))return!1}else for(var a in e){if("$ref"==a)return!1;if(r=e[a],"object"==typeof r&&!l(r))return!1}return!0}function h(e){var r,t=0;if(Array.isArray(e)){for(var a=0;e.length>a;a++)if(r=e[a],"object"==typeof r&&(t+=h(r)),t==1/0)return 1/0}else for(var s in e){if("$ref"==s)return 1/0;if(b[s])t++;else if(r=e[s],"object"==typeof r&&(t+=h(r)+1),t==1/0)return 1/0}return t}function u(e,r){r!==!1&&(e=f(e));var t=m.parse(e,!1,!0);return c(t)}function c(e){return(e.protocol||"")+(e.protocol?"//":"")+(e.host||"")+(e.path||"")+"#"}function f(e){return e?e.replace(E,""):""}function d(e,r){return r=f(r),m.resolve(e,r)}function p(e){function r(e,t,s){if(Array.isArray(e))for(var o=0;e.length>o;o++)r.call(this,e[o],t+"/"+o,s);else if(e&&"object"==typeof e){if("string"==typeof e.id){var i=s=s?m.resolve(s,e.id):f(e.id),n=this._refs[i];if("string"==typeof n&&(n=this._refs[n]),n&&n.schema){if(!v(e,n.schema))throw new Error('id "'+i+'" resolves to more than one schema')}else if(i!=f(t))if("#"==i[0]){if(a[i]&&!v(e,a[i]))throw new Error('id "'+i+'" resolves to more than one schema');a[i]=e}else this._refs[i]=t}for(var l in e)r.call(this,e[l],t+"/"+y.escapeFragment(l),s)}}var t=f(e.id),a={};return r.call(this,e,u(t,!1),t),a}var m=e("url"),v=e("./equal"),y=e("./util"),P=e("./schema_obj");r.exports=a,a.normalizeId=f,a.fullPath=u,a.url=d,a.ids=p,a.inlineRef=n;var g=y.toHash(["properties","patternProperties","enum","dependencies","definitions"]),b=y.toHash(["type","format","pattern","maxLength","minLength","maxProperties","minProperties","maxItems","minItems","maximum","minimum","uniqueItems","multipleOf","required","enum"]),E=/#\/?$/},{"./equal":10,"./schema_obj":15,"./util":16,url:5}],14:[function(e,r,t){"use strict";var a=e("./_rules"),s=e("./util");r.exports=function(){var e=[{type:"number",rules:["maximum","minimum","multipleOf"]},{type:"string",rules:["maxLength","minLength","pattern","format"]},{type:"array",rules:["maxItems","minItems","uniqueItems","items"]},{type:"object",rules:["maxProperties","minProperties","required","dependencies","properties"]},{rules:["$ref","enum","not","anyOf","oneOf","allOf"]}];return e.all=["type","additionalProperties","patternProperties"],e.keywords=["additionalItems","$schema","id","title","description","default"],e.types=["number","integer","string","array","object","boolean","null"],e.forEach(function(r){r.rules=r.rules.map(function(r){return e.all.push(r),{keyword:r,code:a[r]}})}),e.keywords=s.toHash(e.all.concat(e.keywords)),e.all=s.toHash(e.all),e.types=s.toHash(e.types),e}},{"./_rules":9,"./util":16}],15:[function(e,r,t){"use strict";function a(e){s.copy(e,this)}var s=e("./util");r.exports=a},{"./util":16}],16:[function(e,r,t){"use strict";function a(e,r){r=r||{};for(var t in e)r[t]=e[t];return r}function s(e,r,t){var a=t?" !== ":" === ",s=t?" || ":" && ",o=t?"!":"",i=t?"":"!";switch(e){case"null":return r+a+"null";case"array":return o+"Array.isArray("+r+")";case"object":return"("+o+r+s+"typeof "+r+a+'"object"'+s+i+"Array.isArray("+r+"))";case"integer":return"(typeof "+r+a+'"number"'+s+i+"("+r+" % 1))";default:return"typeof "+r+a+'"'+e+'"'}}function o(e,r){switch(e.length){case 1:return s(e[0],r,!0);default:var t="",a=i(e);a.array&&a.object&&(t=a["null"]?"(":"(!"+r+" || ",t+="typeof "+r+' !== "object")',delete a["null"],delete a.array,delete a.object),a.number&&delete a.integer;for(var o in a)t+=(t?" && ":"")+s(o,r,!0);return t}}function i(e){for(var r={},t=0;e.length>t;t++)r[e[t]]=!0;return r}function n(e){return"number"==typeof e?"["+e+"]":x.test(e)?"."+e:"['"+e.replace(R,"\\$&")+"']"}function l(e){return e.replace(R,"\\$&")}function h(e){for(var r,t=0,a=e.length,s=0;a>s;)t++,r=e.charCodeAt(s++),r>=55296&&56319>=r&&a>s&&(r=e.charCodeAt(s),56320==(64512&r)&&s++);return t}function u(e,r){r+="[^0-9]";var t=e.match(new RegExp(r,"g"));return t?t.length:0}function c(e,r,t){return r+="([^0-9])",t=t.replace(/\$/g,"$$$$"),e.replace(new RegExp(r,"g"),t+"$1")}function f(e){return e.replace(S,"").replace(w,"").replace(O,"if (!($1))")}function d(e){var r=e.match(_);return r&&2===r.length?e.replace(k,"").replace(I,A):e}function p(e,r){for(var t in e)if(r[t])return!0}function m(e){return"'"+l(e)+"'"}function v(e,r,t,a){var s=t?"'/' + "+r+(a?"":".replace(/~/g, '~0').replace(/\\//g, '~1')"):a?"'[' + "+r+" + ']'":"'[\\'' + "+r+" + '\\']'";return g(e,s)}function y(e,r,t){var a=m(t?"/"+j(r):n(r));return g(e,a)}function P(e,r,t){var a=e.match(q);if(!a)throw new Error("Invalid relative JSON-pointer: "+e);var s=+a[1],o=a[2];if("#"==o){if(s>=r)throw new Error("Cannot access property/index "+s+" levels up, current level is "+r);return t[r-s]}if(s>r)throw new Error("Cannot access data "+s+" levels up, current level is "+r);var i="data"+(r-s||"");if(!o)return i;for(var l=i,h=o.split("/"),u=0;h.length>u;u++){var c=h[u];c&&(i+=n($(c)),l+=" && "+i)}return l}function g(e,r){return'""'==e?r:(e+" + "+r).replace(/' \+ '/g,"")}function b(e){return $(decodeURIComponent(e));
+}function E(e){return encodeURIComponent(j(e))}function j(e){return e.replace(/~/g,"~0").replace(/\//g,"~1")}function $(e){return e.replace(/~1/g,"/").replace(/~0/g,"~")}r.exports={copy:a,checkDataType:s,checkDataTypes:o,toHash:i,getProperty:n,escapeQuotes:l,ucs2length:h,varOccurences:u,varReplace:c,cleanUpCode:f,cleanUpVarErrors:d,schemaHasRules:p,stableStringify:e("json-stable-stringify"),toQuotedString:m,getPathExpr:v,getPath:y,getData:P,unescapeFragment:b,escapeFragment:E,escapeJsonPointer:j};var x=/^[a-z$_][a-z$_0-9]*$/i,R=/'|\\/g,S=/else\s*{\s*}/g,w=/if\s*\([^)]+\)\s*\{\s*\}(?!\s*else)/g,O=/if\s*\(([^)]+)\)\s*\{\s*\}\s*else(?!\s*if)/g,_=/[^v\.]errors/g,k=/var errors = 0;|var vErrors = null;|validate.errors = vErrors;/g,I="return errors === 0;",A="validate.errors = null; return true;",q=/^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/},{"json-stable-stringify":43}],17:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c="valid"+s;if(a+="var "+c+" = undefined;",e.opts.format===!1)return a+=" "+c+" = true; ";var f=e.schema.format,d=e.opts.v5&&f.$data,p="";if(d){var m=e.util.getData(f.$data,o,e.dataPathArr),v="format"+s,y="compare"+s;a+=" var "+v+" = formats["+m+"] , "+y+" = "+v+" && "+v+".compare;"}else{var v=e.formats[f];if(!v||!v.compare)return a+="  "+c+" = true; ";var y="formats"+e.util.getProperty(f)+".compare"}var P="formatMaximum"==r,g="exclusiveFormat"+(P?"Maximum":"Minimum"),b=e.schema[g],E=e.opts.v5&&b&&b.$data,j=P?"<":">",$="result"+s,x=e.opts.v5&&i.$data,R=x?e.util.getData(i.$data,o,e.dataPathArr):i;if(x&&(a+=" var schema"+s+" = "+R+"; ",R="schema"+s),E){var S=e.util.getData(b.$data,o,e.dataPathArr),w="exclusive"+s,O="op"+s,_="' + "+O+" + '";a+=" var schemaExcl"+s+" = "+S+"; ",S="schemaExcl"+s,a+=" if (typeof "+S+" != 'boolean' && "+S+" !== undefined) { "+c+" = false; ";var t=g,k=k||[];k.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"_exclusiveFormatLimit")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: {} ',e.opts.messages!==!1&&(a+=" , message: '"+g+" should be boolean' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var I=a;a=k.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+I+"]; return false; ":" var err = "+I+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" }  ",h&&(p+="}",a+=" else { "),x&&(a+=" if ("+R+" === undefined) "+c+" = true; else if (typeof "+R+" != 'string') "+c+" = false; else { ",p+="}"),d&&(a+=" if (!"+y+") "+c+" = true; else { ",p+="}"),a+=" var "+$+" = "+y+"("+u+",  ",a+=x?""+R:""+e.util.toQuotedString(i),a+=" ); if ("+$+" === undefined) "+c+" = false; var exclusive"+s+" = "+S+" === true; if ("+c+" === undefined) { "+c+" = exclusive"+s+" ? "+$+" "+j+" 0 : "+$+" "+j+"= 0; } if (!"+c+") var op"+s+" = exclusive"+s+" ? '"+j+"' : '"+j+"=';"}else{var w=b===!0,_=j;w||(_+="=");var O="'"+_+"'";x&&(a+=" if ("+R+" === undefined) "+c+" = true; else if (typeof "+R+" != 'string') "+c+" = false; else { ",p+="}"),d&&(a+=" if (!"+y+") "+c+" = true; else { ",p+="}"),a+=" var "+$+" = "+y+"("+u+",  ",a+=x?""+R:""+e.util.toQuotedString(i),a+=" ); if ("+$+" === undefined) "+c+" = false; if ("+c+" === undefined) "+c+" = "+$+" "+j,w||(a+="="),a+=" 0;"}a+=""+p+"if (!"+c+") { ";var t=r,k=k||[];k.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"_formatLimit")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: { limit:  ',a+=x?""+R:""+e.util.toQuotedString(i),a+="  } ",e.opts.messages!==!1&&(a+=" , message: 'should be "+_+' "',a+=x?"' + "+R+" + '":""+e.util.escapeQuotes(i),a+="\"' "),e.opts.verbose&&(a+=" , schema:  ",a+=x?"validate.schema"+n:""+e.util.toQuotedString(i),a+="         , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var I=a;return a=k.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+I+"]; return false; ":" var err = "+I+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+="}"}},{}],18:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c=e.opts.v5&&i.$data,f=c?e.util.getData(i.$data,o,e.dataPathArr):i;c&&(a+=" var schema"+s+" = "+f+"; ",f="schema"+s);var d="maximum"==r,p=d?"exclusiveMaximum":"exclusiveMinimum",m=e.schema[p],v=e.opts.v5&&m&&m.$data,y=d?"<":">",P=d?">":"<";if(v){var g=e.util.getData(m.$data,o,e.dataPathArr),b="exclusive"+s,E="op"+s,j="' + "+E+" + '";a+=" var schemaExcl"+s+" = "+g+"; ",g="schemaExcl"+s,a+=" var exclusive"+s+"; if (typeof "+g+" != 'boolean' && typeof "+g+" != 'undefined') { ";var t=p,$=$||[];$.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"_exclusiveLimit")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: {} ',e.opts.messages!==!1&&(a+=" , message: '"+p+" should be boolean' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var x=a;a=$.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+x+"]; return false; ":" var err = "+x+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" } else if( ",c&&(a+=" ("+f+" !== undefined && typeof "+f+" != 'number') || "),a+=" ((exclusive"+s+" = "+g+" === true) ? "+u+" "+P+"= "+f+" : "+u+" "+P+" "+f+")) { var op"+s+" = exclusive"+s+" ? '"+y+"' : '"+y+"=';"}else{var b=m===!0,j=y;b||(j+="=");var E="'"+j+"'";a+=" if ( ",c&&(a+=" ("+f+" !== undefined && typeof "+f+" != 'number') || "),a+=" "+u+" "+P,b&&(a+="="),a+=" "+f+") {"}var t=r,$=$||[];$.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"_limit")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: { comparison: '+E+", limit: "+f+", exclusive: "+b+" } ",e.opts.messages!==!1&&(a+=" , message: 'should be "+j+" ",a+=c?"' + "+f:""+i+"'"),e.opts.verbose&&(a+=" , schema:  ",a+=c?"validate.schema"+n:""+i,a+="         , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var x=a;return a=$.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+x+"]; return false; ":" var err = "+x+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" } ",h&&(a+=" else { "),a}},{}],19:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c=e.opts.v5&&i.$data,f=c?e.util.getData(i.$data,o,e.dataPathArr):i;c&&(a+=" var schema"+s+" = "+f+"; ",f="schema"+s);var d="maxItems"==r?">":"<";a+="if ( ",c&&(a+=" ("+f+" !== undefined && typeof "+f+" != 'number') || "),a+=" "+u+".length "+d+" "+f+") { ";var t=r,p=p||[];p.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"_limitItems")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: { limit: '+f+" } ",e.opts.messages!==!1&&(a+=" , message: 'should NOT have ",a+="maxItems"==r?"more":"less",a+=" than ",a+=c?"' + "+f+" + '":""+i,a+=" items' "),e.opts.verbose&&(a+=" , schema:  ",a+=c?"validate.schema"+n:""+i,a+="         , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var m=a;return a=p.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+m+"]; return false; ":" var err = "+m+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+="} ",h&&(a+=" else { "),a}},{}],20:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c=e.opts.v5&&i.$data,f=c?e.util.getData(i.$data,o,e.dataPathArr):i;c&&(a+=" var schema"+s+" = "+f+"; ",f="schema"+s);var d="maxLength"==r?">":"<";a+="if ( ",c&&(a+=" ("+f+" !== undefined && typeof "+f+" != 'number') || "),a+=e.opts.unicode===!1?" "+u+".length ":" ucs2length("+u+") ",a+=" "+d+" "+f+") { ";var t=r,p=p||[];p.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"_limitLength")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: { limit: '+f+" } ",e.opts.messages!==!1&&(a+=" , message: 'should NOT be ",a+="maxLength"==r?"longer":"shorter",a+=" than ",a+=c?"' + "+f+" + '":""+i,a+=" characters' "),e.opts.verbose&&(a+=" , schema:  ",a+=c?"validate.schema"+n:""+i,a+="         , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var m=a;return a=p.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+m+"]; return false; ":" var err = "+m+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+="} ",h&&(a+=" else { "),a}},{}],21:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c=e.opts.v5&&i.$data,f=c?e.util.getData(i.$data,o,e.dataPathArr):i;c&&(a+=" var schema"+s+" = "+f+"; ",f="schema"+s);var d="maxProperties"==r?">":"<";a+="if ( ",c&&(a+=" ("+f+" !== undefined && typeof "+f+" != 'number') || "),a+=" Object.keys("+u+").length "+d+" "+f+") { ";var t=r,p=p||[];p.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"_limitProperties")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: { limit: '+f+" } ",e.opts.messages!==!1&&(a+=" , message: 'should NOT have ",a+="maxProperties"==r?"more":"less",a+=" than ",a+=c?"' + "+f+" + '":""+i,a+=" properties' "),e.opts.verbose&&(a+=" , schema:  ",a+=c?"validate.schema"+n:""+i,a+="         , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var m=a;return a=p.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+m+"]; return false; ":" var err = "+m+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+="} ",h&&(a+=" else { "),a}},{}],22:[function(e,r,t){"use strict";r.exports=function(e,r){var t=" ",a=e.schema[r],s=e.schemaPath+"."+r,o=e.errSchemaPath+"/"+r,i=!e.opts.allErrors,n=e.util.copy(e),l="";n.level++;var h=a;if(h)for(var u,c=-1,f=h.length-1;f>c;)u=h[c+=1],e.util.schemaHasRules(u,e.RULES.all)&&(n.schema=u,n.schemaPath=s+"["+c+"]",n.errSchemaPath=o+"/"+c,t+=" "+e.validate(n)+"  ",i&&(t+=" if (valid"+n.level+") { ",l+="}"));return i&&(t+=" "+l.slice(0,-1)),t=e.util.cleanUpCode(t)}},{}],23:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c="valid"+s,f="errs__"+s,d=e.util.copy(e),p="";d.level++;var m=i.every(function(r){return e.util.schemaHasRules(r,e.RULES.all)});if(m){a+=" var "+f+" = errors; var "+c+" = false;  ";var v=e.compositeRule;e.compositeRule=d.compositeRule=!0;var y=i;if(y)for(var P,g=-1,b=y.length-1;b>g;)P=y[g+=1],d.schema=P,d.schemaPath=n+"["+g+"]",d.errSchemaPath=l+"/"+g,a+=" "+e.validate(d)+" "+c+" = "+c+" || valid"+d.level+"; if (!"+c+") { ",p+="}";e.compositeRule=d.compositeRule=v,a+=" "+p+" if (!"+c+") {  var err =   ",e.createErrors!==!1?(a+=" { keyword: '"+(t||"anyOf")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: {} ',e.opts.messages!==!1&&(a+=" , message: 'should match some schema in anyOf' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ",a+=";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } else {  errors = "+f+"; if (vErrors !== null) { if ("+f+") vErrors.length = "+f+"; else vErrors = null; } ",e.opts.allErrors&&(a+=" } "),a=e.util.cleanUpCode(a)}else h&&(a+=" if (true) { ");return a}},{}],24:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c="valid"+s,f=e.opts.v5&&i.$data,d=f?e.util.getData(i.$data,o,e.dataPathArr):i;f&&(a+=" var schema"+s+" = "+d+"; ",d="schema"+s),f||(a+=" var schema"+s+" = validate.schema"+n+";"),a+="var "+c+" = equal("+u+", schema"+s+"); if (!"+c+") {   ";var p=p||[];p.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"constant")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: {} ',e.opts.messages!==!1&&(a+=" , message: 'should be equal to constant' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var m=a;return a=p.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+m+"]; return false; ":" var err = "+m+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" }"}},{}],25:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c="errs__"+s,f=e.util.copy(e),d="";f.level++;var p={},m={};for(g in i){var v=i[g],y=Array.isArray(v)?m:p;y[g]=v}a+="var "+c+" = errors;";var P=e.errorPath;a+="var missing"+s+";";for(var g in m){y=m[g],a+=" if ("+u+e.util.getProperty(g)+" !== undefined && ( ";var b=y;if(b)for(var E,j=-1,$=b.length-1;$>j;){E=b[j+=1],j&&(a+=" || ");var x=e.util.getProperty(E);a+=" ( "+u+x+" === undefined && (missing"+s+" = "+e.util.toQuotedString(e.opts.jsonPointers?E:x)+") ) "}a+=")) {  ";var R="missing"+s,S="' + "+R+" + '";e.opts._errorDataPathProperty&&(e.errorPath=e.opts.jsonPointers?e.util.getPathExpr(P,R,!0):P+" + "+R);var w=w||[];w.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"dependencies")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+"\" , params: { property: '"+e.util.escapeQuotes(g)+"', missingProperty: '"+S+"', depsCount: "+y.length+", deps: '"+e.util.escapeQuotes(1==y.length?y[0]:y.join(", "))+"' } ",e.opts.messages!==!1&&(a+=" , message: 'should have ",a+=1==y.length?"property "+e.util.escapeQuotes(y[0]):"properties "+e.util.escapeQuotes(y.join(", ")),a+=" when property "+e.util.escapeQuotes(g)+" is present' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var O=a;a=w.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+O+"]; return false; ":" var err = "+O+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" }   ",h&&(d+="}",a+=" else { ")}e.errorPath=P;for(var g in p){var v=p[g];e.util.schemaHasRules(v,e.RULES.all)&&(a+=" valid"+f.level+" = true; if ("+u+"['"+g+"'] !== undefined) { ",f.schema=v,f.schemaPath=n+e.util.getProperty(g),f.errSchemaPath=l+"/"+e.util.escapeFragment(g),a+=" "+e.validate(f)+" }  ",h&&(a+=" if (valid"+f.level+") { ",d+="}"))}return h&&(a+="   "+d+" if ("+c+" == errors) {"),a=e.util.cleanUpCode(a)}},{}],26:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c="valid"+s,f=e.opts.v5&&i.$data,d=f?e.util.getData(i.$data,o,e.dataPathArr):i;f&&(a+=" var schema"+s+" = "+d+"; ",d="schema"+s);var p="i"+s;f||(a+=" var schema"+s+" = validate.schema"+n+";"),a+="var "+c+";",f&&(a+=" if (schema"+s+" === undefined) "+c+" = true; else if (!Array.isArray(schema"+s+")) "+c+" = false; else {"),a+=""+c+" = false;for (var "+p+"=0; "+p+"<schema"+s+".length; "+p+"++) if (equal("+u+", schema"+s+"["+p+"])) { "+c+" = true; break; }",f&&(a+="  }  "),a+=" if (!"+c+") {   ";var m=m||[];m.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"enum")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: {} ',e.opts.messages!==!1&&(a+=" , message: 'should be equal to one of values' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var v=a;return a=m.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+v+"]; return false; ":" var err = "+v+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" }",h&&(a+=" else { "),a}},{}],27:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||"");if(e.opts.format===!1)return h&&(a+=" if (true) { "),a;var c=e.opts.v5&&i.$data,f=c?e.util.getData(i.$data,o,e.dataPathArr):i;if(c&&(a+=" var schema"+s+" = "+f+"; ",f="schema"+s),c){var d="format"+s;a+=" var "+d+" = formats["+f+"]; var isObject"+s+" = typeof "+d+" == 'object' && !("+d+" instanceof RegExp) && "+d+".validate; if (isObject"+s+") "+d+" = "+d+".validate;   if (  ",c&&(a+=" ("+f+" !== undefined && typeof "+f+" != 'string') || "),a+=" ("+d+" && !(typeof "+d+" == 'function' ? "+d+"("+u+") : "+d+".test("+u+")))) {"}else{var d=e.formats[i];if(!d)return h&&(a+=" if (true) { "),a;var p="object"==typeof d&&!(d instanceof RegExp)&&d.validate;p&&(d=d.validate),a+=" if (! ";var m="formats"+e.util.getProperty(i);p&&(m+=".validate"),a+="function"==typeof d?" "+m+"("+u+") ":" "+m+".test("+u+") ",a+=") {"}var v=v||[];v.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"format")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: { format:  ',a+=c?""+f:""+e.util.toQuotedString(i),a+="  } ",e.opts.messages!==!1&&(a+=" , message: 'should match format \"",a+=c?"' + "+f+" + '":""+e.util.escapeQuotes(i),a+="\"' "),e.opts.verbose&&(a+=" , schema:  ",a+=c?"validate.schema"+n:""+e.util.toQuotedString(i),a+="         , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var y=a;return a=v.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+y+"]; return false; ":" var err = "+y+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" } ",h&&(a+=" else { "),a}},{}],28:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c="valid"+s,f="errs__"+s,d=e.util.copy(e),p="";d.level++;var m=d.dataLevel=e.dataLevel+1,v="data"+m;if(a+="var "+f+" = errors;var "+c+";",Array.isArray(i)){var y=e.schema.additionalItems;if(y===!1){a+=" "+c+" = "+u+".length <= "+i.length+"; ";var P=l;l=e.errSchemaPath+"/additionalItems",a+="  if (!"+c+") {   ";var g=g||[];g.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"additionalItems")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: { limit: '+i.length+" } ",e.opts.messages!==!1&&(a+=" , message: 'should NOT have more than "+i.length+" items' "),e.opts.verbose&&(a+=" , schema: false , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var b=a;a=g.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+b+"]; return false; ":" var err = "+b+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" } ",l=P,h&&(p+="}",a+=" else { ")}var E=i;if(E)for(var j,$=-1,x=E.length-1;x>$;)if(j=E[$+=1],e.util.schemaHasRules(j,e.RULES.all)){a+=" valid"+d.level+" = true; if ("+u+".length > "+$+") { ";var R=u+"["+$+"]";d.schema=j,d.schemaPath=n+"["+$+"]",d.errSchemaPath=l+"/"+$,d.errorPath=e.util.getPathExpr(e.errorPath,$,e.opts.jsonPointers,!0),e.opts.v5&&(d.dataPathArr[m]=$);var S=e.validate(d);a+=e.util.varOccurences(S,v)<2?" "+e.util.varReplace(S,v,R)+" ":" var "+v+" = "+R+"; "+S+" ",a+=" }  ",h&&(a+=" if (valid"+d.level+") { ",p+="}")}if("object"==typeof y&&e.util.schemaHasRules(y,e.RULES.all)){d.schema=y,d.schemaPath=e.schemaPath+".additionalItems",d.errSchemaPath=e.errSchemaPath+"/additionalItems",a+=" valid"+d.level+" = true; if ("+u+".length > "+i.length+") {  for (var i"+s+" = "+i.length+"; i"+s+" < "+u+".length; i"+s+"++) { ",d.errorPath=e.util.getPathExpr(e.errorPath,"i"+s,e.opts.jsonPointers,!0);var R=u+"[i"+s+"]";e.opts.v5&&(d.dataPathArr[m]="i"+s);var S=e.validate(d);a+=e.util.varOccurences(S,v)<2?" "+e.util.varReplace(S,v,R)+" ":" var "+v+" = "+R+"; "+S+" ",h&&(a+=" if (!valid"+d.level+") break; "),a+=" } }  ",h&&(a+=" if (valid"+d.level+") { ",p+="}")}}else if(e.util.schemaHasRules(i,e.RULES.all)){d.schema=i,d.schemaPath=n,d.errSchemaPath=l,a+="  for (var i"+s+" = 0; i"+s+" < "+u+".length; i"+s+"++) { ",d.errorPath=e.util.getPathExpr(e.errorPath,"i"+s,e.opts.jsonPointers,!0);var R=u+"[i"+s+"]";e.opts.v5&&(d.dataPathArr[m]="i"+s);var S=e.validate(d);a+=e.util.varOccurences(S,v)<2?" "+e.util.varReplace(S,v,R)+" ":" var "+v+" = "+R+"; "+S+" ",h&&(a+=" if (!valid"+d.level+") break; "),a+=" }  ",h&&(a+=" if (valid"+d.level+") { ",p+="}")}return h&&(a+=" "+p+" if ("+f+" == errors) {"),a=e.util.cleanUpCode(a)}},{}],29:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c=e.opts.v5&&i.$data,f=c?e.util.getData(i.$data,o,e.dataPathArr):i;c&&(a+=" var schema"+s+" = "+f+"; ",f="schema"+s),a+="var division"+s+";if (",c&&(a+=" "+f+" !== undefined && ( typeof "+f+" != 'number' || "),a+=" (division"+s+" = "+u+" / "+f+", ",a+=e.opts.multipleOfPrecision?" Math.abs(Math.round(division"+s+") - division"+s+") > 1e-"+e.opts.multipleOfPrecision+" ":" division"+s+" !== parseInt(division"+s+") ",a+=" ) ",c&&(a+="  )  "),a+=" ) {   ";var d=d||[];d.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"multipleOf")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: { multipleOf: '+f+" } ",e.opts.messages!==!1&&(a+=" , message: 'should be multiple of ",a+=c?"' + "+f:""+i+"'"),e.opts.verbose&&(a+=" , schema:  ",a+=c?"validate.schema"+n:""+i,a+="         , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var p=a;return a=d.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+p+"]; return false; ":" var err = "+p+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+="} ",h&&(a+=" else { "),a}},{}],30:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c="errs__"+s,f=e.util.copy(e);if(f.level++,e.util.schemaHasRules(i,e.RULES.all)){f.schema=i,f.schemaPath=n,f.errSchemaPath=l,a+=" var "+c+" = errors;  ";var d=e.compositeRule;e.compositeRule=f.compositeRule=!0,f.createErrors=!1,a+=" "+e.validate(f)+" ",f.createErrors=!0,e.compositeRule=f.compositeRule=d,a+=" if (valid"+f.level+") {   ";var p=p||[];p.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"not")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: {} ',e.opts.messages!==!1&&(a+=" , message: 'should NOT be valid' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var m=a;a=p.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+m+"]; return false; ":" var err = "+m+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" } else {  errors = "+c+"; if (vErrors !== null) { if ("+c+") vErrors.length = "+c+"; else vErrors = null; } ",e.opts.allErrors&&(a+=" } ")}else a+="  var err =   ",e.createErrors!==!1?(a+=" { keyword: '"+(t||"not")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: {} ',e.opts.messages!==!1&&(a+=" , message: 'should NOT be valid' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ",a+=";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",h&&(a+=" if (false) { ");return a}},{}],31:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c="valid"+s,f="errs__"+s,d=e.util.copy(e),p="";d.level++,a+="var "+f+" = errors;var prevValid"+s+" = false;var "+c+" = false; ";var m=e.compositeRule;e.compositeRule=d.compositeRule=!0;var v=i;if(v)for(var y,P=-1,g=v.length-1;g>P;)y=v[P+=1],e.util.schemaHasRules(y,e.RULES.all)?(d.schema=y,d.schemaPath=n+"["+P+"]",d.errSchemaPath=l+"/"+P,a+=" "+e.validate(d)+" "):a+=" var valid"+d.level+" = true; ",P&&(a+=" if (valid"+d.level+" && prevValid"+s+") "+c+" = false; else { ",p+="}"),a+=" if (valid"+d.level+") "+c+" = prevValid"+s+" = true;";e.compositeRule=d.compositeRule=m,a+=""+p+"if (!"+c+") {   ";var b=b||[];b.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"oneOf")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: {} ',e.opts.messages!==!1&&(a+=" , message: 'should match exactly one schema in oneOf' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var E=a;return a=b.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+E+"]; return false; ":" var err = "+E+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+="} else {  errors = "+f+"; if (vErrors !== null) { if ("+f+") vErrors.length = "+f+"; else vErrors = null; }",e.opts.allErrors&&(a+=" } "),a}},{}],32:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c=e.opts.v5&&i.$data,f=c?e.util.getData(i.$data,o,e.dataPathArr):i;c&&(a+=" var schema"+s+" = "+f+"; ",f="schema"+s);var d=c?"(new RegExp("+f+"))":e.usePattern(i);a+="if ( ",c&&(a+=" ("+f+" !== undefined && typeof "+f+" != 'string') || "),a+=" !"+d+".test("+u+") ) {   ";var p=p||[];p.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"pattern")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: { pattern:  ',a+=c?""+f:""+e.util.toQuotedString(i),a+="  } ",e.opts.messages!==!1&&(a+=" , message: 'should match pattern \"",a+=c?"' + "+f+" + '":""+e.util.escapeQuotes(i),a+="\"' "),e.opts.verbose&&(a+=" , schema:  ",a+=c?"validate.schema"+n:""+e.util.toQuotedString(i),a+="         , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var m=a;return a=p.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+m+"]; return false; ":" var err = "+m+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+="} ",h&&(a+=" else { "),a}},{}],33:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c="valid"+s,f="errs__"+s,d=e.util.copy(e),p="";d.level++;var m=d.dataLevel=e.dataLevel+1,v="data"+m,y=Object.keys(i||{}),P=e.schema.patternProperties||{},g=Object.keys(P),b=e.schema.additionalProperties,E=y.length||g.length,j=b===!1,$="object"==typeof b&&Object.keys(b).length,x=e.opts.removeAdditional,R=j||$||x,S=e.schema.required;if(S&&(!e.opts.v5||!S.$data)&&e.opts.loopRequired>S.length)var w=e.util.toHash(S);if(e.opts.v5)var O=e.schema.patternGroups||{},_=Object.keys(O);if(a+="var "+f+" = errors;var valid"+d.level+" = true;",R){if(a+=" for (var key"+s+" in "+u+") { ",E){if(a+=" var isAdditional"+s+" = !(false ",y.length)if(y.length>5)a+=" || validate.schema"+n+"[key"+s+"] ";else{var k=y;if(k)for(var I,A=-1,q=k.length-1;q>A;)I=k[A+=1],a+=" || key"+s+" == "+e.util.toQuotedString(I)+" "}if(g.length){var L=g;if(L)for(var C,D=-1,U=L.length-1;U>D;)C=L[D+=1],a+=" || "+e.usePattern(C)+".test(key"+s+") "}if(e.opts.v5&&_&&_.length){var z=_;if(z)for(var M,D=-1,T=z.length-1;T>D;)M=z[D+=1],a+=" || "+e.usePattern(M)+".test(key"+s+") "}a+=" ); if (isAdditional"+s+") { "}if("all"==x)a+=" delete "+u+"[key"+s+"]; ";else{var Q=e.errorPath,H="' + key"+s+" + '";if(e.opts._errorDataPathProperty&&(e.errorPath=e.util.getPathExpr(e.errorPath,"key"+s,e.opts.jsonPointers)),j)if(x)a+=" delete "+u+"[key"+s+"]; ";else{a+=" valid"+d.level+" = false; ";var N=l;l=e.errSchemaPath+"/additionalProperties";var V=V||[];V.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"additionalProperties")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+"\" , params: { additionalProperty: '"+H+"' } ",e.opts.messages!==!1&&(a+=" , message: 'should NOT have additional properties' "),e.opts.verbose&&(a+=" , schema: false , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var F=a;a=V.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+F+"]; return false; ":" var err = "+F+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",l=N,h&&(a+=" break; ")}else if($)if("failing"==x){a+=" var "+f+" = errors;  ";var G=e.compositeRule;e.compositeRule=d.compositeRule=!0,d.schema=b,d.schemaPath=e.schemaPath+".additionalProperties",d.errSchemaPath=e.errSchemaPath+"/additionalProperties",d.errorPath=e.opts._errorDataPathProperty?e.errorPath:e.util.getPathExpr(e.errorPath,"key"+s,e.opts.jsonPointers);var K=u+"[key"+s+"]";e.opts.v5&&(d.dataPathArr[m]="key"+s);var J=e.validate(d);a+=e.util.varOccurences(J,v)<2?" "+e.util.varReplace(J,v,K)+" ":" var "+v+" = "+K+"; "+J+" ",a+=" if (!valid"+d.level+") { errors = "+f+"; if (validate.errors !== null) { if (errors) validate.errors.length = errors; else validate.errors = null; } delete "+u+"[key"+s+"]; }  ",e.compositeRule=d.compositeRule=G}else{d.schema=b,d.schemaPath=e.schemaPath+".additionalProperties",d.errSchemaPath=e.errSchemaPath+"/additionalProperties",d.errorPath=e.opts._errorDataPathProperty?e.errorPath:e.util.getPathExpr(e.errorPath,"key"+s,e.opts.jsonPointers);var K=u+"[key"+s+"]";e.opts.v5&&(d.dataPathArr[m]="key"+s);var J=e.validate(d);a+=e.util.varOccurences(J,v)<2?" "+e.util.varReplace(J,v,K)+" ":" var "+v+" = "+K+"; "+J+" ",h&&(a+=" if (!valid"+d.level+") break; ")}e.errorPath=Q}E&&(a+=" } "),a+=" }  ",h&&(a+=" if (valid"+d.level+") { ",p+="}")}var B=e.opts.useDefaults&&!e.compositeRule;if(y.length){var Z=y;if(Z)for(var I,W=-1,X=Z.length-1;X>W;){I=Z[W+=1];var Y=i[I];if(e.util.schemaHasRules(Y,e.RULES.all)){var ee=e.util.getProperty(I),K=u+ee,re=B&&void 0!==Y["default"];d.schema=Y,d.schemaPath=n+ee,d.errSchemaPath=l+"/"+e.util.escapeFragment(I),d.errorPath=e.util.getPath(e.errorPath,I,e.opts.jsonPointers),e.opts.v5&&(d.dataPathArr[m]=e.util.toQuotedString(I));var J=e.validate(d);if(e.util.varOccurences(J,v)<2){J=e.util.varReplace(J,v,K);var te=K}else{var te=v;a+=" var "+v+" = "+K+"; "}if(re)a+=" "+J+" ";else{if(w&&w[I]){a+=" if ("+te+" === undefined) { valid"+d.level+" = false; ";var Q=e.errorPath,N=l,ae=e.util.escapeQuotes(I);e.opts._errorDataPathProperty&&(e.errorPath=e.util.getPath(Q,I,e.opts.jsonPointers)),l=e.errSchemaPath+"/required";var V=V||[];V.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"required")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+"\" , params: { missingProperty: '"+ae+"' } ",e.opts.messages!==!1&&(a+=" , message: '",a+=e.opts._errorDataPathProperty?"is a required property":"should have required property \\'"+ae+"\\'",a+="' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var F=a;a=V.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+F+"]; return false; ":" var err = "+F+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",l=N,e.errorPath=Q,a+=" } else { "}else a+=h?" if ("+te+" === undefined) { valid"+d.level+" = true; } else { ":" if ("+te+" !== undefined) { ";a+=" "+J+" } "}}h&&(a+=" if (valid"+d.level+") { ",p+="}")}}var se=g;if(se)for(var C,oe=-1,ie=se.length-1;ie>oe;){C=se[oe+=1];var Y=P[C];if(e.util.schemaHasRules(Y,e.RULES.all)){d.schema=Y,d.schemaPath=e.schemaPath+".patternProperties"+e.util.getProperty(C),d.errSchemaPath=e.errSchemaPath+"/patternProperties/"+e.util.escapeFragment(C),
+a+=" for (var key"+s+" in "+u+") { if ("+e.usePattern(C)+".test(key"+s+")) { ",d.errorPath=e.util.getPathExpr(e.errorPath,"key"+s,e.opts.jsonPointers);var K=u+"[key"+s+"]";e.opts.v5&&(d.dataPathArr[m]="key"+s);var J=e.validate(d);a+=e.util.varOccurences(J,v)<2?" "+e.util.varReplace(J,v,K)+" ":" var "+v+" = "+K+"; "+J+" ",h&&(a+=" if (!valid"+d.level+") break; "),a+=" } ",h&&(a+=" else valid"+d.level+" = true; "),a+=" }  ",h&&(a+=" if (valid"+d.level+") { ",p+="}")}}if(e.opts.v5){var ne=_;if(ne)for(var M,le=-1,he=ne.length-1;he>le;){M=ne[le+=1];var ue=O[M],Y=ue.schema;if(e.util.schemaHasRules(Y,e.RULES.all)){d.schema=Y,d.schemaPath=e.schemaPath+".patternGroups"+e.util.getProperty(M)+".schema",d.errSchemaPath=e.errSchemaPath+"/patternGroups/"+e.util.escapeFragment(M)+"/schema",a+=" var pgPropCount"+s+" = 0; for (var key"+s+" in "+u+") { if ("+e.usePattern(M)+".test(key"+s+")) { pgPropCount"+s+"++; ",d.errorPath=e.util.getPathExpr(e.errorPath,"key"+s,e.opts.jsonPointers);var K=u+"[key"+s+"]";e.opts.v5&&(d.dataPathArr[m]="key"+s);var J=e.validate(d);a+=e.util.varOccurences(J,v)<2?" "+e.util.varReplace(J,v,K)+" ":" var "+v+" = "+K+"; "+J+" ",h&&(a+=" if (!valid"+d.level+") break; "),a+=" } ",h&&(a+=" else valid"+d.level+" = true; "),a+=" }  ",h&&(a+=" if (valid"+d.level+") { ",p+="}");var ce=ue.minimum,fe=ue.maximum;if(void 0!==ce||void 0!==fe){a+=" var "+c+" = true; ";var N=l;if(void 0!==ce){var de=ce,pe="minimum",me="less";a+=" "+c+" = pgPropCount"+s+" >= "+ce+"; ",l=e.errSchemaPath+"/patternGroups/minimum",a+="  if (!"+c+") {   ";var V=V||[];V.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"patternGroups")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+"\" , params: { reason: '"+pe+"', limit: "+de+", pattern: '"+e.util.escapeQuotes(M)+"' } ",e.opts.messages!==!1&&(a+=" , message: 'should NOT have "+me+" than "+de+' properties matching pattern "'+e.util.escapeQuotes(M)+"\"' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var F=a;a=V.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+F+"]; return false; ":" var err = "+F+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" } ",void 0!==fe&&(a+=" else ")}if(void 0!==fe){var de=fe,pe="maximum",me="more";a+=" "+c+" = pgPropCount"+s+" <= "+fe+"; ",l=e.errSchemaPath+"/patternGroups/maximum",a+="  if (!"+c+") {   ";var V=V||[];V.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"patternGroups")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+"\" , params: { reason: '"+pe+"', limit: "+de+", pattern: '"+e.util.escapeQuotes(M)+"' } ",e.opts.messages!==!1&&(a+=" , message: 'should NOT have "+me+" than "+de+' properties matching pattern "'+e.util.escapeQuotes(M)+"\"' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var F=a;a=V.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+F+"]; return false; ":" var err = "+F+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" } "}l=N,h&&(a+=" if ("+c+") { ",p+="}")}}}}return h&&(a+=" "+p+" if ("+f+" == errors) {"),a=e.util.cleanUpCode(a)}},{}],34:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.dataLevel,o=e.schema[r],i=e.errSchemaPath+"/"+r,n=!e.opts.allErrors,l="data"+(s||"");if("#"==o||"#/"==o)e.isRoot?(a+="  if (! validate("+l+", (dataPath || '')",'""'!=e.errorPath&&(a+=" + "+e.errorPath),a+=") ) { if (vErrors === null) vErrors = validate.errors; else vErrors = vErrors.concat(validate.errors); errors = vErrors.length; } ",n&&(a+=" else { ")):(a+="  if (! root.refVal[0]("+l+", (dataPath || '')",'""'!=e.errorPath&&(a+=" + "+e.errorPath),a+=") ) { if (vErrors === null) vErrors = root.refVal[0].errors; else vErrors = vErrors.concat(root.refVal[0].errors); errors = vErrors.length; } ",n&&(a+=" else { "));else{var h=e.resolveRef(e.baseId,o,e.isRoot);if(void 0===h){var u="can't resolve reference "+o+" from id "+e.baseId;if("fail"==e.opts.missingRefs){console.log(u);var c=c||[];c.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"$ref")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+i+"\" , params: { ref: '"+e.util.escapeQuotes(o)+"' } ",e.opts.messages!==!1&&(a+=" , message: 'can\\'t resolve reference "+e.util.escapeQuotes(o)+"' "),e.opts.verbose&&(a+=" , schema: "+e.util.toQuotedString(o)+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+l+" "),a+=" } "):a+=" {} ";var f=a;a=c.pop(),a+=!e.compositeRule&&n?" validate.errors = ["+f+"]; return false; ":" var err = "+f+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",n&&(a+=" if (false) { ")}else{if("ignore"!=e.opts.missingRefs){var d=new Error(u);throw d.missingRef=e.resolve.url(e.baseId,o),d.missingSchema=e.resolve.normalizeId(e.resolve.fullPath(d.missingRef)),d}console.log(u),n&&(a+=" if (true) { ")}}else if("string"==typeof h)a+="  if (! "+h+"("+l+", (dataPath || '')",'""'!=e.errorPath&&(a+=" + "+e.errorPath),a+=") ) { if (vErrors === null) vErrors = "+h+".errors; else vErrors = vErrors.concat("+h+".errors); errors = vErrors.length; } ",n&&(a+=" else { ");else{var p=e.util.copy(e);p.level++,p.schema=h.schema,p.schemaPath="",p.errSchemaPath=o;var m=e.validate(p).replace(/validate\.schema/g,h.code);a+=" "+m+" ",n&&(a+=" if (valid"+p.level+") { ")}}return a}},{}],35:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c="valid"+s,f=e.opts.v5&&i.$data,d=f?e.util.getData(i.$data,o,e.dataPathArr):i;if(f&&(a+=" var schema"+s+" = "+d+"; ",d="schema"+s),!f)if(e.opts.loopRequired>i.length&&e.schema.properties&&Object.keys(e.schema.properties).length){var p=[],m=i;if(m)for(var v,y=-1,P=m.length-1;P>y;){v=m[y+=1];var g=e.schema.properties[v];g&&e.util.schemaHasRules(g,e.RULES.all)||(p[p.length]=v)}}else var p=i;if(f||p.length){var b=e.errorPath,E=f||p.length>=e.opts.loopRequired;if(h)if(a+=" var missing"+s+"; ",E){f||(a+=" var schema"+s+" = validate.schema"+n+"; ");var j="i"+s,$="schema"+s+"["+j+"]",x="' + "+$+" + '";e.opts._errorDataPathProperty&&(e.errorPath=e.util.getPathExpr(b,$,e.opts.jsonPointers)),a+=" var "+c+" = true; ",f&&(a+=" if (schema"+s+" === undefined) "+c+" = true; else if (!Array.isArray(schema"+s+")) "+c+" = false; else {"),a+=" for (var "+j+" = 0; "+j+" < schema"+s+".length; "+j+"++) { "+c+" = "+u+"[schema"+s+"["+j+"]] !== undefined; if (!"+c+") break; } ",f&&(a+="  }  "),a+="  if (!"+c+") {   ";var R=R||[];R.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"required")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+"\" , params: { missingProperty: '"+x+"' } ",e.opts.messages!==!1&&(a+=" , message: '",a+=e.opts._errorDataPathProperty?"is a required property":"should have required property \\'"+x+"\\'",a+="' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var S=a;a=R.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+S+"]; return false; ":" var err = "+S+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" } else { "}else{a+=" if ( ";var w=p;if(w)for(var O,j=-1,_=w.length-1;_>j;){O=w[j+=1],j&&(a+=" || ");var k=e.util.getProperty(O);a+=" ( "+u+k+" === undefined && (missing"+s+" = "+e.util.toQuotedString(e.opts.jsonPointers?O:k)+") ) "}a+=") {  ";var $="missing"+s,x="' + "+$+" + '";e.opts._errorDataPathProperty&&(e.errorPath=e.opts.jsonPointers?e.util.getPathExpr(b,$,!0):b+" + "+$);var R=R||[];R.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"required")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+"\" , params: { missingProperty: '"+x+"' } ",e.opts.messages!==!1&&(a+=" , message: '",a+=e.opts._errorDataPathProperty?"is a required property":"should have required property \\'"+x+"\\'",a+="' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var S=a;a=R.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+S+"]; return false; ":" var err = "+S+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" } else { "}else if(E){f||(a+=" var schema"+s+" = validate.schema"+n+"; ");var j="i"+s,$="schema"+s+"["+j+"]",x="' + "+$+" + '";e.opts._errorDataPathProperty&&(e.errorPath=e.util.getPathExpr(b,$,e.opts.jsonPointers)),f&&(a+=" if (schema"+s+" && !Array.isArray(schema"+s+")) {  var err =   ",e.createErrors!==!1?(a+=" { keyword: '"+(t||"required")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+"\" , params: { missingProperty: '"+x+"' } ",e.opts.messages!==!1&&(a+=" , message: '",a+=e.opts._errorDataPathProperty?"is a required property":"should have required property \\'"+x+"\\'",a+="' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ",a+=";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } else if (schema"+s+" !== undefined) { "),a+=" for (var "+j+" = 0; "+j+" < schema"+s+".length; "+j+"++) { if ("+u+"[schema"+s+"["+j+"]] === undefined) {  var err =   ",e.createErrors!==!1?(a+=" { keyword: '"+(t||"required")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+"\" , params: { missingProperty: '"+x+"' } ",e.opts.messages!==!1&&(a+=" , message: '",a+=e.opts._errorDataPathProperty?"is a required property":"should have required property \\'"+x+"\\'",a+="' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ",a+=";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } } ",f&&(a+="  }  ")}else{var I=p;if(I)for(var v,j=-1,A=I.length-1;A>j;){v=I[j+=1];var k=e.util.getProperty(v),x=e.util.escapeQuotes(v);e.opts._errorDataPathProperty&&(e.errorPath=e.util.getPath(b,v,e.opts.jsonPointers)),a+=" if ("+u+k+" === undefined) {  var err =   ",e.createErrors!==!1?(a+=" { keyword: '"+(t||"required")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+"\" , params: { missingProperty: '"+x+"' } ",e.opts.messages!==!1&&(a+=" , message: '",a+=e.opts._errorDataPathProperty?"is a required property":"should have required property \\'"+x+"\\'",a+="' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ",a+=";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } "}}e.errorPath=b}else h&&(a+=" if (true) {");return a}},{}],36:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c="valid"+s,f="errs__"+s,d=e.util.copy(e),p="";d.level++;var m,v="ifPassed"+e.level;a+="var "+v+";";var y=i;if(y)for(var P,g=-1,b=y.length-1;b>g;){if(P=y[g+=1],g&&!m&&(a+=" if (!"+v+") { ",p+="}"),P["if"]&&e.util.schemaHasRules(P["if"],e.RULES.all)){a+=" var "+f+" = errors;   ";var E=e.compositeRule;if(e.compositeRule=d.compositeRule=!0,d.createErrors=!1,d.schema=P["if"],d.schemaPath=n+"["+g+"].if",d.errSchemaPath=l+"/"+g+"/if",a+=" "+e.validate(d)+" ",d.createErrors=!0,e.compositeRule=d.compositeRule=E,a+=" "+v+" = valid"+d.level+"; if ("+v+") {  ","boolean"==typeof P.then){if(P.then===!1){var j=j||[];j.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"switch")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: { caseIndex: '+g+" } ",e.opts.messages!==!1&&(a+=" , message: 'should pass \"switch\" keyword validation' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var $=a;a=j.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+$+"]; return false; ":" var err = "+$+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; "}a+=" var valid"+d.level+" = "+P.then+"; "}else d.schema=P.then,d.schemaPath=n+"["+g+"].then",d.errSchemaPath=l+"/"+g+"/then",a+=" "+e.validate(d)+" ";a+="  } else {  errors = "+f+"; if (vErrors !== null) { if ("+f+") vErrors.length = "+f+"; else vErrors = null; } } "}else if(a+=" "+v+" = true;  ","boolean"==typeof P.then){if(P.then===!1){var j=j||[];j.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"switch")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: { caseIndex: '+g+" } ",e.opts.messages!==!1&&(a+=" , message: 'should pass \"switch\" keyword validation' "),e.opts.verbose&&(a+=" , schema: validate.schema"+n+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var $=a;a=j.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+$+"]; return false; ":" var err = "+$+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; "}a+=" var valid"+d.level+" = "+P.then+"; "}else d.schema=P.then,d.schemaPath=n+"["+g+"].then",d.errSchemaPath=l+"/"+g+"/then",a+=" "+e.validate(d)+" ";m=P["continue"]}return a+=""+p+"var "+c+" = valid"+d.level+"; ",a=e.util.cleanUpCode(a)}},{}],37:[function(e,r,t){"use strict";r.exports=function(e,r){var t,a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+"."+r,l=e.errSchemaPath+"/"+r,h=!e.opts.allErrors,u="data"+(o||""),c="valid"+s,f=e.opts.v5&&i.$data,d=f?e.util.getData(i.$data,o,e.dataPathArr):i;if(f&&(a+=" var schema"+s+" = "+d+"; ",d="schema"+s),(i||f)&&e.opts.uniqueItems!==!1){f&&(a+=" var "+c+"; if ("+d+" === false || "+d+" === undefined) "+c+" = true; else if (typeof "+d+" != 'boolean') "+c+" = false; else { "),a+=" var "+c+" = true; if ("+u+".length > 1) { var i = "+u+".length, j; outer: for (;i--;) { for (j = i; j--;) { if (equal("+u+"[i], "+u+"[j])) { "+c+" = false; break outer; } } } } ",f&&(a+="  }  "),a+=" if (!"+c+") {   ";var p=p||[];p.push(a),a="",e.createErrors!==!1?(a+=" { keyword: '"+(t||"uniqueItems")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+l+'" , params: { i: i, j: j } ',e.opts.messages!==!1&&(a+=" , message: 'should NOT have duplicate items (items ## ' + j + ' and ' + i + ' are identical)' "),e.opts.verbose&&(a+=" , schema:  ",a+=f?"validate.schema"+n:""+i,a+="         , parentSchema: validate.schema"+e.schemaPath+" , data: "+u+" "),a+=" } "):a+=" {} ";var m=a;a=p.pop(),a+=!e.compositeRule&&h?" validate.errors = ["+m+"]; return false; ":" var err = "+m+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",a+=" } ",h&&(a+=" else { ")}else h&&(a+=" if (true) { ");return a}},{}],38:[function(e,r,t){"use strict";r.exports=function(e,r){function t(e){for(var r=0;e.rules.length>r;r++)if(a(e.rules[r]))return!0}function a(r){return void 0!==e.schema[r.keyword]||"properties"==r.keyword&&(e.schema.additionalProperties===!1||"object"==typeof e.schema.additionalProperties||e.schema.patternProperties&&Object.keys(e.schema.patternProperties).length||e.opts.v5&&e.schema.patternGroups&&Object.keys(e.schema.patternGroups).length)}var s="";if(e.isTop){var o=e.isTop,i=e.level=0,n=e.dataLevel=0,l="data";e.rootId=e.resolve.fullPath(e.root.schema.id),e.baseId=e.baseId||e.rootId,delete e.isTop,e.opts.v5&&(e.dataPathArr=[void 0]),s+=" validate = function (data, dataPath) { 'use strict'; var vErrors = null; ",s+=" var errors = 0;     "}else{var i=e.level,n=e.dataLevel,l="data"+(n||"");e.schema.id&&(e.baseId=e.resolve.url(e.baseId,e.schema.id)),s+=" var errs_"+i+" = errors;"}var h,u="valid"+i,c=!e.opts.allErrors,f="",d="",p=e.schema.type,m=e.RULES;if(m)for(var v,y=-1,P=m.length-1;P>y;)if(v=m[y+=1],t(v)){if(v.type&&(s+=" if ("+e.util.checkDataType(v.type,l)+") { "),e.opts.useDefaults&&!e.compositeRule)if("object"==v.type&&e.schema.properties){var g=e.schema.properties,b=Object.keys(g),E=b;if(E)for(var j,$=-1,x=E.length-1;x>$;){j=E[$+=1];var R=g[j];if(void 0!==R["default"]){var S=l+e.util.getProperty(j);s+="  if ("+S+" === undefined) "+S+" = "+e.useDefault(R["default"])+"; "}}}else if("array"==v.type&&Array.isArray(e.schema.items)){var w=e.schema.items;if(w)for(var R,O=-1,_=w.length-1;_>O;)if(R=w[O+=1],void 0!==R["default"]){var S=l+"["+O+"]";s+="  if ("+S+" === undefined) "+S+" = "+e.useDefault(R["default"])+"; "}}var k=v.rules;if(k)for(var I,A=-1,q=k.length-1;q>A;)if(I=k[A+=1],a(I)){if(I.custom){var g=e.schema[I.keyword],L=e.useCustomRule(I,g,e.schema,e),C=L.code+".errors",D=e.schemaPath+"."+I.keyword,U=e.errSchemaPath+"/"+I.keyword,z="errs"+i,O="i"+i,M="ruleErr"+i,T=I.definition,Q=T.inline,H=T.macro;if(Q||H||(s+=""+C+" = null;"),s+="var "+z+" = errors;",Q&&T.statements)s+=" "+L.validate;else if(H){var N=e.util.copy(e);N.level++,N.schema=L.validate,N.schemaPath="";var V=e.compositeRule;e.compositeRule=N.compositeRule=!0;var F=e.validate(N).replace(/validate\.schema/g,L.code);e.compositeRule=N.compositeRule=V,s+=" "+F}s+="if (! ",Q?s+=T.statements?" valid"+i+" ":" ("+L.validate+") ":H?s+=" valid"+N.level+" ":(s+=" "+L.code+".call(self ",T.compile?s+=" , "+l+" ":(s+=" , validate.schema"+D+" , "+l+" ",L.validate.length>2&&(s+=" , validate.schema"+e.schemaPath+" ")),s+=" ) "),s+=") { ",h=I.keyword;var G=G||[];G.push(s),s="";var G=G||[];G.push(s),s="",e.createErrors!==!1?(s+=" { keyword: '"+(h||"custom")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+U+"\" , params: { keyword: '"+I.keyword+"' } ",e.opts.messages!==!1&&(s+=" , message: 'should pass \""+I.keyword+"\" keyword validation' "),e.opts.verbose&&(s+=" , schema: validate.schema"+D+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+l+" "),s+=" } "):s+=" {} ";var K=s;s=G.pop(),s+=!e.compositeRule&&c?" validate.errors = ["+K+"]; return false; ":" var err = "+K+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ";var J=s;s=G.pop(),Q?T.errors?"full"!=T.errors&&(s+="  for (var "+O+"="+z+"; "+O+"<errors; "+O+"++) { var "+M+" = vErrors["+O+"]; if ("+M+".dataPath === undefined) { "+M+".dataPath = (dataPath || '') + "+e.errorPath+"; } ",e.opts.verbose&&(s+=" "+M+".schema = validate.schema"+D+"; "+M+".data = "+l+"; "),s+=" } "):T.errors===!1?s+=" "+J+" ":(s+=" if ("+z+" == errors) { "+J+" } else {  for (var "+O+"="+z+"; "+O+"<errors; "+O+"++) { var "+M+" = vErrors["+O+"]; if ("+M+".dataPath === undefined) { "+M+".dataPath = (dataPath || '') + "+e.errorPath+"; } ",e.opts.verbose&&(s+=" "+M+".schema = validate.schema"+D+"; "+M+".data = "+l+"; "),s+=" } } "):H?(s+="   var err =   ",e.createErrors!==!1?(s+=" { keyword: '"+(h||"custom")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+U+"\" , params: { keyword: '"+I.keyword+"' } ",e.opts.messages!==!1&&(s+=" , message: 'should pass \""+I.keyword+"\" keyword validation' "),e.opts.verbose&&(s+=" , schema: validate.schema"+D+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+l+" "),s+=" } "):s+=" {} ",s+=";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",!e.compositeRule&&c&&(s+=" validate.errors = vErrors; return false ")):(s+=" if (Array.isArray("+C+")) { if (vErrors === null) vErrors = "+C+"; else vErrors.concat("+C+"); errors = vErrors.length;  for (var "+O+"="+z+"; "+O+"<errors; "+O+"++) { var "+M+" = vErrors["+O+"];  "+M+".dataPath = (dataPath || '') + "+e.errorPath+";  ",e.opts.verbose&&(s+=" "+M+".schema = validate.schema"+D+"; "+M+".data = "+l+"; "),s+=" } } else { "+J+" } "),h=void 0,s+=" } ",c&&(s+=" else { ")}else s+=" "+I.code(e,I.keyword)+" ";c&&(f+="}")}if(c&&(s+=" "+f+" ",f=""),v.type&&(s+=" } ",p&&p===v.type)){var B=!0;s+=" else { ";var D=e.schemaPath+".type",U=e.errSchemaPath+"/type",G=G||[];G.push(s),s="",e.createErrors!==!1?(s+=" { keyword: '"+(h||"type")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+U+"\" , params: { type: '",s+=Z?""+p.join(","):""+p,s+="' } ",e.opts.messages!==!1&&(s+=" , message: 'should be ",s+=Z?""+p.join(","):""+p,s+="' "),e.opts.verbose&&(s+=" , schema: validate.schema"+D+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+l+" "),s+=" } "):s+=" {} ";var K=s;s=G.pop(),s+=!e.compositeRule&&c?" validate.errors = ["+K+"]; return false; ":" var err = "+K+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",s+=" } "}c&&(s+=" if (errors === ",s+=o?"0":"errs_"+i,s+=") { ",d+="}")}if(p&&!B){var D=e.schemaPath+".type",U=e.errSchemaPath+"/type",Z=Array.isArray(p),W=Z?"checkDataTypes":"checkDataType";s+=" if ("+e.util[W](p,l,!0)+") {   ";var G=G||[];G.push(s),s="",e.createErrors!==!1?(s+=" { keyword: '"+(h||"type")+"' , dataPath: (dataPath || '') + "+e.errorPath+' , schemaPath: "'+U+"\" , params: { type: '",s+=Z?""+p.join(","):""+p,s+="' } ",e.opts.messages!==!1&&(s+=" , message: 'should be ",s+=Z?""+p.join(","):""+p,s+="' "),e.opts.verbose&&(s+=" , schema: validate.schema"+D+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+l+" "),s+=" } "):s+=" {} ";var K=s;s=G.pop(),s+=!e.compositeRule&&c?" validate.errors = ["+K+"]; return false; ":" var err = "+K+";  if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",s+=" }"}return c&&(s+=" "+d+" "),o?(s+=" validate.errors = vErrors; ",s+=" return errors === 0;       ",s+=" }"):s+=" var "+u+" = errors === errs_"+i+";",s=e.util.cleanUpCode(s),o&&c&&(s=e.util.cleanUpVarErrors(s)),s}},{}],39:[function(e,r,t){"use strict";var a=/^[a-z_$][a-z0-9_$]*$/i;r.exports=function(e,r){function t(e,r,t){for(var a,s=0;o.RULES.length>s;s++){var i=o.RULES[s];if(i.type==r){a=i;break}}a||(a={type:r,rules:[]},o.RULES.push(a));var n={keyword:e,definition:t,custom:!0};a.rules.push(n)}function s(e){if(!o.RULES.types[e])throw new Error("Unknown type "+e)}var o=this;if(this.RULES.keywords[e])throw new Error("Keyword "+e+" is already defined");if(!a.test(e))throw new Error("Keyword "+e+" is not a valid identifier");if(r){var i=r.type;if(Array.isArray(i)){var n,l=i.length;for(n=0;l>n;n++)s(i[n]);for(n=0;l>n;n++)t(e,i[n],r)}else i&&s(i),t(e,i,r)}this.RULES.keywords[e]=!0,this.RULES.all[e]=!0}},{}],40:[function(e,r,t){r.exports={id:"http://json-schema.org/draft-04/schema#",$schema:"http://json-schema.org/draft-04/schema#",description:"Core schema meta-schema",definitions:{schemaArray:{type:"array",minItems:1,items:{$ref:"#"}},positiveInteger:{type:"integer",minimum:0},positiveIntegerDefault0:{allOf:[{$ref:"#/definitions/positiveInteger"},{"default":0}]},simpleTypes:{"enum":["array","boolean","integer","null","number","object","string"]},stringArray:{type:"array",items:{type:"string"},minItems:1,uniqueItems:!0}},type:"object",properties:{id:{type:"string",format:"uri"},$schema:{type:"string",format:"uri"},title:{type:"string"},description:{type:"string"},"default":{},multipleOf:{type:"number",minimum:0,exclusiveMinimum:!0},maximum:{type:"number"},exclusiveMaximum:{type:"boolean","default":!1},minimum:{type:"number"},exclusiveMinimum:{type:"boolean","default":!1},maxLength:{$ref:"#/definitions/positiveInteger"},minLength:{$ref:"#/definitions/positiveIntegerDefault0"},pattern:{type:"string",format:"regex"},additionalItems:{anyOf:[{type:"boolean"},{$ref:"#"}],"default":{}},items:{anyOf:[{$ref:"#"},{$ref:"#/definitions/schemaArray"}],"default":{}},maxItems:{$ref:"#/definitions/positiveInteger"},minItems:{$ref:"#/definitions/positiveIntegerDefault0"},uniqueItems:{type:"boolean","default":!1},maxProperties:{$ref:"#/definitions/positiveInteger"},minProperties:{$ref:"#/definitions/positiveIntegerDefault0"},required:{$ref:"#/definitions/stringArray"},additionalProperties:{anyOf:[{type:"boolean"},{$ref:"#"}],"default":{}},definitions:{type:"object",additionalProperties:{$ref:"#"},"default":{}},properties:{type:"object",additionalProperties:{$ref:"#"},"default":{}},patternProperties:{type:"object",additionalProperties:{$ref:"#"},"default":{}},dependencies:{type:"object",additionalProperties:{anyOf:[{$ref:"#"},{$ref:"#/definitions/stringArray"}]}},"enum":{type:"array",minItems:1,uniqueItems:!0},type:{anyOf:[{$ref:"#/definitions/simpleTypes"},{type:"array",items:{$ref:"#/definitions/simpleTypes"},minItems:1,uniqueItems:!0}]},allOf:{$ref:"#/definitions/schemaArray"},anyOf:{$ref:"#/definitions/schemaArray"},oneOf:{$ref:"#/definitions/schemaArray"},not:{$ref:"#"}},dependencies:{exclusiveMaximum:["maximum"],exclusiveMinimum:["minimum"]},"default":{}}},{}],41:[function(e,r,t){r.exports={id:"https://raw.githubusercontent.com/epoberezkin/ajv/master/lib/refs/json-schema-v5.json#",$schema:"http://json-schema.org/draft-04/schema#",description:"Core schema meta-schema (v5 proposals)",definitions:{schemaArray:{type:"array",minItems:1,items:{$ref:"#"}},positiveInteger:{type:"integer",minimum:0},positiveIntegerDefault0:{allOf:[{$ref:"#/definitions/positiveInteger"},{"default":0}]},simpleTypes:{"enum":["array","boolean","integer","null","number","object","string"]},stringArray:{type:"array",items:{type:"string"},minItems:1,uniqueItems:!0},$data:{type:"object",required:["$data"],properties:{$data:{type:"string",format:"relative-json-pointer"}},additionalProperties:!1}},type:"object",properties:{id:{type:"string",format:"uri"},$schema:{type:"string",format:"uri"},title:{type:"string"},description:{type:"string"},"default":{},multipleOf:{anyOf:[{type:"number",minimum:0,exclusiveMinimum:!0},{$ref:"#/definitions/$data"}]},maximum:{anyOf:[{type:"number"},{$ref:"#/definitions/$data"}]},exclusiveMaximum:{anyOf:[{type:"boolean","default":!1},{$ref:"#/definitions/$data"}]},minimum:{anyOf:[{type:"number"},{$ref:"#/definitions/$data"}]},exclusiveMinimum:{anyOf:[{type:"boolean","default":!1},{$ref:"#/definitions/$data"}]},maxLength:{anyOf:[{$ref:"#/definitions/positiveInteger"},{$ref:"#/definitions/$data"}]},minLength:{anyOf:[{$ref:"#/definitions/positiveIntegerDefault0"},{$ref:"#/definitions/$data"}]},pattern:{anyOf:[{type:"string",format:"regex"},{$ref:"#/definitions/$data"}]},additionalItems:{anyOf:[{type:"boolean"},{$ref:"#"},{$ref:"#/definitions/$data"}],"default":{}},items:{anyOf:[{$ref:"#"},{$ref:"#/definitions/schemaArray"}],"default":{}},maxItems:{anyOf:[{$ref:"#/definitions/positiveInteger"},{$ref:"#/definitions/$data"}]},minItems:{anyOf:[{$ref:"#/definitions/positiveIntegerDefault0"},{$ref:"#/definitions/$data"}]},uniqueItems:{anyOf:[{type:"boolean","default":!1},{$ref:"#/definitions/$data"}]},maxProperties:{anyOf:[{$ref:"#/definitions/positiveInteger"},{$ref:"#/definitions/$data"}]},minProperties:{anyOf:[{$ref:"#/definitions/positiveIntegerDefault0"},{$ref:"#/definitions/$data"}]},required:{anyOf:[{$ref:"#/definitions/stringArray"},{$ref:"#/definitions/$data"}]},additionalProperties:{anyOf:[{type:"boolean"},{$ref:"#"},{$ref:"#/definitions/$data"}],"default":{}},definitions:{type:"object",additionalProperties:{$ref:"#"},"default":{}},properties:{type:"object",additionalProperties:{$ref:"#"},"default":{}},patternProperties:{type:"object",additionalProperties:{$ref:"#"},"default":{}},dependencies:{type:"object",additionalProperties:{anyOf:[{$ref:"#"},{$ref:"#/definitions/stringArray"}]}},"enum":{anyOf:[{type:"array",minItems:1,uniqueItems:!0},{$ref:"#/definitions/$data"}]},type:{anyOf:[{$ref:"#/definitions/simpleTypes"},{type:"array",items:{$ref:"#/definitions/simpleTypes"},minItems:1,uniqueItems:!0}]},allOf:{$ref:"#/definitions/schemaArray"},anyOf:{$ref:"#/definitions/schemaArray"},oneOf:{$ref:"#/definitions/schemaArray"},not:{$ref:"#"},format:{anyOf:[{type:"string"},{$ref:"#/definitions/$data"}]},formatMaximum:{anyOf:[{type:"string"},{$ref:"#/definitions/$data"}]},formatMinimum:{anyOf:[{type:"string"},{$ref:"#/definitions/$data"}]},exclusiveFormatMaximum:{anyOf:[{type:"boolean","default":!1},{$ref:"#/definitions/$data"}]},exclusiveFormatMinimum:{anyOf:[{type:"boolean","default":!1},{$ref:"#/definitions/$data"}]},constant:{anyOf:[{},{$ref:"#/definitions/$data"}]},contains:{$ref:"#"},patternGroups:{type:"object",additionalProperties:{type:"object",required:["schema"],properties:{maximum:{anyOf:[{$ref:"#/definitions/positiveInteger"},{$ref:"#/definitions/$data"}]},minimum:{anyOf:[{$ref:"#/definitions/positiveIntegerDefault0"},{$ref:"#/definitions/$data"}]},schema:{$ref:"#"}},additionalProperties:!1},"default":{}},"switch":{type:"array",items:{required:["then"],properties:{"if":{$ref:"#"},then:{anyOf:[{type:"boolean"},{$ref:"#"}]},"continue":{type:"boolean"}},additionalProperties:!1,dependencies:{"continue":["if"]}}}},dependencies:{exclusiveMaximum:["maximum"],exclusiveMinimum:["minimum"],formatMaximum:["format"],formatMinimum:["format"],exclusiveFormatMaximum:["formatMaximum"],exclusiveFormatMinimum:["formatMinimum"]},"default":{}}},{}],42:[function(e,r,t){"use strict";function a(r){if(r.opts.meta!==!1){var t=e("./refs/json-schema-v5.json");r.addMetaSchema(t,o)}r.addKeyword("constant",{inline:e("./dotjs/constant"),statements:!0,errors:"full"}),r.addKeyword("contains",{type:"array",macro:s});var a=e("./dotjs/_formatLimit");r.addKeyword("formatMaximum",{type:"string",inline:a,statements:!0,errors:"full"}),r.addKeyword("formatMinimum",{type:"string",inline:a,statements:!0,errors:"full"}),r.addKeyword("exclusiveFormatMaximum"),r.addKeyword("exclusiveFormatMinimum"),r.addKeyword("patternGroups"),r.addKeyword("switch",{inline:e("./dotjs/switch"),statements:!0,errors:"full"})}function s(e){return{not:{items:{not:e}}}}var o="https://raw.githubusercontent.com/epoberezkin/ajv/master/lib/refs/json-schema-v5.json";r.exports={enable:a,META_SCHEMA_ID:o}},{"./dotjs/_formatLimit":17,"./dotjs/constant":24,"./dotjs/switch":36,"./refs/json-schema-v5.json":41}],43:[function(e,r,t){var a="undefined"!=typeof JSON?JSON:e("jsonify");r.exports=function(e,r){r||(r={}),"function"==typeof r&&(r={cmp:r});var t=r.space||"";"number"==typeof t&&(t=Array(t+1).join(" "));var i="boolean"==typeof r.cycles?r.cycles:!1,n=r.replacer||function(e,r){return r},l=r.cmp&&function(e){return function(r){return function(t,a){var s={key:t,value:r[t]},o={key:a,value:r[a]};return e(s,o)}}}(r.cmp),h=[];return function u(e,r,c,f){var d=t?"\n"+new Array(f+1).join(t):"",p=t?": ":":";if(c&&c.toJSON&&"function"==typeof c.toJSON&&(c=c.toJSON()),c=n.call(e,r,c),void 0!==c){if("object"!=typeof c||null===c)return a.stringify(c);if(s(c)){for(var m=[],v=0;c.length>v;v++){var y=u(c,v,c[v],f+1)||a.stringify(null);m.push(d+t+y)}return"["+m.join(",")+d+"]"}if(-1!==h.indexOf(c)){if(i)return a.stringify("__cycle__");throw new TypeError("Converting circular structure to JSON")}h.push(c);for(var P=o(c).sort(l&&l(c)),m=[],v=0;P.length>v;v++){var r=P[v],g=u(c,r,c[r],f+1);if(g){var b=a.stringify(r)+p+g;m.push(d+t+b)}}return"{"+m.join(",")+d+"}"}}({"":e},"",e,0)};var s=Array.isArray||function(e){return"[object Array]"==={}.toString.call(e)},o=Object.keys||function(e){var r=Object.prototype.hasOwnProperty||function(){return!0},t=[];for(var a in e)r.call(e,a)&&t.push(a);return t}},{jsonify:44}],44:[function(e,r,t){t.parse=e("./lib/parse"),t.stringify=e("./lib/stringify")},{"./lib/parse":45,"./lib/stringify":46}],45:[function(e,r,t){var a,s,o,i,n={'"':'"',"\\":"\\","/":"/",b:"\b",f:"\f",n:"\n",r:"\r",t:"	"},l=function(e){throw{name:"SyntaxError",message:e,at:a,text:o}},h=function(e){return e&&e!==s&&l("Expected '"+e+"' instead of '"+s+"'"),s=o.charAt(a),a+=1,s},u=function(){var e,r="";for("-"===s&&(r="-",h("-"));s>="0"&&"9">=s;)r+=s,h();if("."===s)for(r+=".";h()&&s>="0"&&"9">=s;)r+=s;if("e"===s||"E"===s)for(r+=s,h(),("-"===s||"+"===s)&&(r+=s,h());s>="0"&&"9">=s;)r+=s,h();return e=+r,isFinite(e)?e:void l("Bad number")},c=function(){var e,r,t,a="";if('"'===s)for(;h();){if('"'===s)return h(),a;if("\\"===s)if(h(),"u"===s){for(t=0,r=0;4>r&&(e=parseInt(h(),16),isFinite(e));r+=1)t=16*t+e;a+=String.fromCharCode(t)}else{if("string"!=typeof n[s])break;a+=n[s]}else a+=s}l("Bad string")},f=function(){for(;s&&" ">=s;)h()},d=function(){switch(s){case"t":return h("t"),h("r"),h("u"),h("e"),!0;case"f":return h("f"),h("a"),h("l"),h("s"),h("e"),!1;case"n":return h("n"),
+h("u"),h("l"),h("l"),null}l("Unexpected '"+s+"'")},p=function(){var e=[];if("["===s){if(h("["),f(),"]"===s)return h("]"),e;for(;s;){if(e.push(i()),f(),"]"===s)return h("]"),e;h(","),f()}}l("Bad array")},m=function(){var e,r={};if("{"===s){if(h("{"),f(),"}"===s)return h("}"),r;for(;s;){if(e=c(),f(),h(":"),Object.hasOwnProperty.call(r,e)&&l('Duplicate key "'+e+'"'),r[e]=i(),f(),"}"===s)return h("}"),r;h(","),f()}}l("Bad object")};i=function(){switch(f(),s){case"{":return m();case"[":return p();case'"':return c();case"-":return u();default:return s>="0"&&"9">=s?u():d()}},r.exports=function(e,r){var t;return o=e,a=0,s=" ",t=i(),f(),s&&l("Syntax error"),"function"==typeof r?function n(e,t){var a,s,o=e[t];if(o&&"object"==typeof o)for(a in o)Object.prototype.hasOwnProperty.call(o,a)&&(s=n(o,a),void 0!==s?o[a]=s:delete o[a]);return r.call(e,t,o)}({"":t},""):t}},{}],46:[function(e,r,t){function a(e){return l.lastIndex=0,l.test(e)?'"'+e.replace(l,function(e){var r=h[e];return"string"==typeof r?r:"\\u"+("0000"+e.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+e+'"'}function s(e,r){var t,l,h,u,c,f=o,d=r[e];switch(d&&"object"==typeof d&&"function"==typeof d.toJSON&&(d=d.toJSON(e)),"function"==typeof n&&(d=n.call(r,e,d)),typeof d){case"string":return a(d);case"number":return isFinite(d)?String(d):"null";case"boolean":case"null":return String(d);case"object":if(!d)return"null";if(o+=i,c=[],"[object Array]"===Object.prototype.toString.apply(d)){for(u=d.length,t=0;u>t;t+=1)c[t]=s(t,d)||"null";return h=0===c.length?"[]":o?"[\n"+o+c.join(",\n"+o)+"\n"+f+"]":"["+c.join(",")+"]",o=f,h}if(n&&"object"==typeof n)for(u=n.length,t=0;u>t;t+=1)l=n[t],"string"==typeof l&&(h=s(l,d),h&&c.push(a(l)+(o?": ":":")+h));else for(l in d)Object.prototype.hasOwnProperty.call(d,l)&&(h=s(l,d),h&&c.push(a(l)+(o?": ":":")+h));return h=0===c.length?"{}":o?"{\n"+o+c.join(",\n"+o)+"\n"+f+"}":"{"+c.join(",")+"}",o=f,h}}var o,i,n,l=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,h={"\b":"\\b","	":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};r.exports=function(e,r,t){var a;if(o="",i="","number"==typeof t)for(a=0;t>a;a+=1)i+=" ";else"string"==typeof t&&(i=t);if(n=r,r&&"function"!=typeof r&&("object"!=typeof r||"number"!=typeof r.length))throw new Error("JSON.stringify");return s("",{"":e})}},{}],ajv:[function(e,r,t){"use strict";function a(e){return d.test(e)}function Ajv(r){function t(e,r){var t;if("string"==typeof e){if(t=P(e),!t)throw new Error('no schema with key or ref "'+e+'"')}else{var a=E(e);t=a.validate||j(a)}var s=t(r);return O.errors=t.errors,s}function p(e){var r=E(e);return r.validate||j(r)}function m(e,r,t,a){if(Array.isArray(e))for(var s=0;e.length>s;s++)m(e[s]);else{r=o.normalizeId(r||e.id),w(r);var i=O._schemas[r]=E(e,t,!0);i.meta=a}}function v(e,r,t){m(e,r,t,!0)}function y(e,r){var s=e.$schema||(O.opts.v5?c.META_SCHEMA_ID:f),o=O._formats.uri;O._formats.uri="function"==typeof o?a:d;var i=t(s,e);if(O._formats.uri=o,!i&&r){var n="schema is invalid:"+$();if("log"!=O.opts.validateSchema)throw new Error(n);console.error(n)}return i}function P(e){var r=g(e);switch(typeof r){case"object":return r.validate||j(r);case"string":return P(r)}}function g(e){return e=o.normalizeId(e),O._schemas[e]||O._refs[e]}function b(e){switch(typeof e){case"string":var r=g(e);O._cache.del(r.jsonStr),delete O._schemas[e],delete O._refs[e];break;case"object":var t=l(e);O._cache.del(t);var a=e.id;a&&(a=o.normalizeId(a),delete O._refs[a])}}function E(e,r,t){if("object"!=typeof e)throw new Error("schema should be object");var a=l(e),s=O._cache.get(a);if(s)return s;t=t||O.opts.addUsedSchema!==!1;var i=o.normalizeId(e.id);i&&t&&w(i),O.opts.validateSchema===!1||r||y(e,!0);var h=o.ids.call(O,e),u=new n({id:i,schema:e,localRefs:h,jsonStr:a});return"#"!=i[0]&&t&&(O._refs[i]=u),O._cache.put(a,u),u}function j(e,r){function t(){var r=e.validate,a=r.apply(null,arguments);return t.errors=r.errors,a}if(e.compiling)return e.validate=t,t.schema=e.schema,t.errors=null,t.root=r?r:t,t;e.compiling=!0;var a=O.opts.removeAdditional,o=O.opts.useDefaults;e.meta&&(a&&(O.opts.removeAdditional=!1),o&&(O.opts.useDefaults=!1));var i;try{i=s.call(O,e.schema,r,e.localRefs)}finally{e.compiling=!1,a&&(O.opts.removeAdditional=a),o&&(O.opts.useDefaults=o)}return e.validate=i,e.refs=i.refs,e.refVal=i.refVal,e.root=i.root,i}function $(e,r){if(e=e||O.errors,!e)return"No errors";r=r||{};for(var t=r.separator||", ",a=r.dataVar||"data",s="",o=0;e.length>o;o++){var i=e[o];i&&(s+=a+i.dataPath+" "+i.message+t)}return s.slice(0,-t.length)}function x(e,r){"string"==typeof r&&(r=new RegExp(r)),O._formats[e]=r}function R(){if(O.opts.meta!==!1){var r=e("./refs/json-schema-draft-04.json");v(r,f,!0),O._refs["http://json-schema.org/schema"]=f}var t=O.opts.schemas;if(t)if(Array.isArray(t))m(t);else for(var a in t)m(t[a],a)}function S(){for(var e in O.opts.formats){var r=O.opts.formats[e];x(e,r)}}function w(e){if(O._schemas[e]||O._refs[e])throw new Error('schema with key or id "'+e+'" already exists')}if(!(this instanceof Ajv))return new Ajv(r);var O=this;this.opts=r||{},this._schemas={},this._refs={},this._formats=h(this.opts.format),this._cache=this.opts.cache||new i,this._loadingSchemas={},this.RULES=u(),this.validate=t,this.compile=p,this.addSchema=m,this.addMetaSchema=v,this.validateSchema=y,this.getSchema=P,this.removeSchema=b,this.addFormat=x,this.errorsText=$,this._addSchema=E,this._compile=j,R(),this.opts.formats&&S(),"property"==this.opts.errorDataPath&&(this.opts._errorDataPathProperty=!0),this.opts.v5&&c.enable(this),this.opts.loopRequired=this.opts.loopRequired||1/0}var s=e("./compile"),o=e("./compile/resolve"),i=e("./cache"),n=e("./compile/schema_obj"),l=e("json-stable-stringify"),h=e("./compile/formats"),u=e("./compile/rules"),c=e("./v5");r.exports=Ajv,Ajv.prototype.compileAsync=e("./async"),Ajv.prototype.addKeyword=e("./keyword");var f="http://json-schema.org/draft-04/schema",d=/^(?:(?:[a-z][a-z0-9+-.]*:)?\/\/)?[^\s]*$/i},{"./async":7,"./cache":8,"./compile":12,"./compile/formats":11,"./compile/resolve":13,"./compile/rules":14,"./compile/schema_obj":15,"./keyword":39,"./refs/json-schema-draft-04.json":40,"./v5":42,"json-stable-stringify":43}]},{},[])("ajv")});
+//# sourceMappingURL=ajv.min.js.map
\ No newline at end of file
diff --git a/htdocs/Libs/AJV/ajv.min.js.map b/htdocs/Libs/AJV/ajv.min.js.map
new file mode 100644
index 0000000..09eaa8d
--- /dev/null
+++ b/htdocs/Libs/AJV/ajv.min.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["ajv.bundle.js"],"names":["f","exports","module","define","amd","g","window","global","self","this","Ajv","e","t","n","r","s","o","u","a","require","i","Error","code","l","call","length",1,"root","error","type","RangeError","errors","map","array","fn","result","mapDomain","string","parts","split","replace","regexSeparators","labels","encoded","join","ucs2decode","value","extra","output","counter","charCodeAt","push","ucs2encode","stringFromCharCode","basicToDigit","codePoint","base","digitToBasic","digit","flag","adapt","delta","numPoints","firstTime","k","floor","damp","baseMinusTMin","tMax","skew","decode","input","out","basic","j","index","oldi","w","baseMinusT","inputLength","initialN","bias","initialBias","lastIndexOf","delimiter","maxInt","tMin","splice","encode","handledCPCount","basicLength","m","q","currentValue","handledCPCountPlusOne","qMinusT","toUnicode","regexPunycode","test","slice","toLowerCase","toASCII","regexNonASCII","freeExports","nodeType","freeModule","freeGlobal","punycode","key","overflow","not-basic","invalid-input","Math","String","fromCharCode","version","ucs2","hasOwnProperty",2,"obj","prop","Object","prototype","qs","sep","eq","options","regexp","maxKeys","len","kstr","vstr","v","x","idx","indexOf","substr","decodeURIComponent","isArray","Array","xs","toString",3,"res","stringifyPrimitive","isFinite","name","undefined","objectKeys","ks","encodeURIComponent","keys",4,"parse","stringify","./decode","./encode",5,"Url","protocol","slashes","auth","host","port","hostname","hash","search","query","pathname","path","href","urlParse","url","parseQueryString","slashesDenoteHost","util","isObject","urlFormat","isString","format","urlResolve","source","relative","resolve","urlResolveObject","resolveObject","protocolPattern","portPattern","simplePathPattern","delims","unwise","concat","autoEscape","nonHostChars","hostEndingChars","hostnameMaxLen","hostnamePartPattern","hostnamePartStart","unsafeProtocol","javascript","javascript:","hostlessProtocol","slashedProtocol","http","https","ftp","gopher","file","http:","https:","ftp:","gopher:","file:","querystring","TypeError","queryIndex","splitter","uSplit","slashRegex","rest","trim","simplePath","exec","proto","lowerProto","match","hostEnd","hec","atSign","parseHost","ipv6Hostname","hostparts","part","newpart","validParts","notHost","bit","unshift","p","h","ae","esc","escape","qm","charAt","rel","tkeys","tk","tkey","rkeys","rk","rkey","relPath","shift","isSourceAbs","isRelAbs","mustEndAbs","removeAllDots","srcPath","psychotic","pop","isNullOrUndefined","authInHost","isNull","last","hasTrailingSlash","up","isAbsolute","./util",6,"arg",7,"schema","callback","_compileAsync","firstCall","loadMissingSchema","schemaLoaded","err","sch","_refs","ref","_schemas","addSchema","missingSchema","missingRef","_callbacks","_loadingSchemas","opts","loadSchema","deferCallback","validate","setTimeout","compile","schemaObj","_addSchema",8,"Cache","_cache","put","get","del",9,"$ref","allOf","anyOf","dependencies","enum","items","maximum","minimum","maxItems","minItems","maxLength","minLength","maxProperties","minProperties","multipleOf","not","oneOf","pattern","properties","required","uniqueItems","../dotjs/_limit","../dotjs/_limitItems","../dotjs/_limitLength","../dotjs/_limitProperties","../dotjs/allOf","../dotjs/anyOf","../dotjs/dependencies","../dotjs/enum","../dotjs/format","../dotjs/items","../dotjs/multipleOf","../dotjs/not","../dotjs/oneOf","../dotjs/pattern","../dotjs/properties","../dotjs/ref","../dotjs/required","../dotjs/uniqueItems","../dotjs/validate",10,"equal","b","arrA","arrB",11,"formats","mode","formatDefs","copy","fName","compare","date","str","matches","DATE","month","day","DAYS","time","full","TIME","hour","minute","second","timeZone","date_time","dateTime","DATE_TIME_SEPARATOR","HOSTNAME","uri","NOT_URI_FRAGMENT","URI","regex","RegExp","compareDate","d1","d2","compareTime","t1","t2","compareDateTime","dt1","dt2","UUID","JSON_POINTER","RELATIVE_JSON_POINTER","fast","date-time","email","ipv4","ipv6","uuid","json-pointer","relative-json-pointer",12,"localRefs","baseId","localCompile","_schema","_root","isRoot","validateCode","validateGenerator","isTop","schemaPath","errSchemaPath","errorPath","RULES","resolveRef","usePattern","useDefault","useCustomRule","vars","refVal","refValCode","patterns","patternCode","defaults","defaultCode","customRules","customRuleCode","beautify","indent_size","console","eval","log","refs","_refVal","refCode","refIndex","resolvedRef","rootRefId","addLocalRef","localSchema","inlineRef","inlineRefs","replaceLocalRef","refId","regexStr","patternsHash","toQuotedString","valueStr","stableStringify","defaultsHash","rule","parentSchema","it","definition","inline","macro","validateSchema","keyword","customRulesHash","_formats","arr","statement","js_beautify","ucs2length","./equal","./resolve","json-stable-stringify",13,"SchemaObject","_compile","_resolve","refPath","_getFullPath","getFullPath","id","normalizeId","resolveRecursive","getJsonPointer","parsedRef","resolveUrl","unescapeFragment","PREVENT_SCOPE_CHANGE","limit","checkNoRef","countKeys","item","count","Infinity","SIMPLE_INLINED","normalize","TRAILING_SLASH_HASH","resolveIds","_resolveIds","fullPath","escapeFragment","ids","toHash","./schema_obj",14,"ruleModules","rules","all","keywords","types","forEach","group","./_rules",15,16,"to","checkDataType","dataType","data","negate","EQUAL","AND","OK","NOT","checkDataTypes","dataTypes","object","number","integer","getProperty","IDENTIFIER","SINGLE_QUOTE","escapeQuotes","pos","varOccurences","dataVar","varReplace","expr","cleanUpCode","EMPTY_ELSE","EMPTY_IF_NO_ELSE","EMPTY_IF_WITH_ELSE","cleanUpVarErrors","ERRORS_REGEXP","REMOVE_ERRORS","RETURN_VALID","RETURN_TRUE","schemaHasRules","getPathExpr","currentPath","jsonPointers","isNumber","joinPaths","getPath","escapeJsonPointer","getData","$data","lvl","paths","jsonPointer","segments","segment","unescapeJsonPointer",17,"$keyword","$errorKeyword","$lvl","level","$dataLvl","dataLevel","$schema","$schemaPath","$errSchemaPath","$breakOnError","allErrors","$valid","$schemaFormat","$isDataFormat","v5","$closingBraces","$schemaValueFormat","dataPathArr","$format","$compare","$isMax","$exclusiveKeyword","$schemaExcl","$isDataExcl","$op","$result","$isData","$schemaValue","$schemaValueExcl","$exclusive","$opExpr","$opStr","$$outStack","createErrors","messages","verbose","__err","compositeRule",18,"$notOp",19,20,"unicode",21,22,"$it","arr1","$sch","$i","l1",23,"$errs","$noEmptySchema","every","$wasComposite",24,25,"$schemaDeps","$propertyDeps","$property","$deps","$currentErrorPath","_$property","$prop","$propertyPath","$missingProperty","_errorDataPathProperty",26,27,"$isObject","$formatRef",28,"$dataNxt","$nextData","$additionalItems","additionalItems","$currErrSchemaPath","$passData","$code",29,"multipleOfPrecision",30,31,32,"$regexp",33,"$schemaKeys","$pProperties","patternProperties","$pPropertyKeys","$aProperties","additionalProperties","$someProperties","$noAdditional","$additionalIsSchema","$removeAdditional","removeAdditional","$checkAdditional","$required","loopRequired","$requiredHash","$pgProperties","patternGroups","$pgPropertyKeys","$propertyKey","i1","arr2","$pProperty","l2","arr3","$pgProperty","l3","$additionalProperty","$useDefaults","useDefaults","arr4","i4","l4","$hasDefault","$useData","arr5","i5","l5","arr6","i6","l6","$pgSchema","$pgMin","$pgMax","$limit","$reason","$moreOrLess",34,"$refVal","$message","missingRefs","$error",35,"$propertySch","$loopRequired",36,"$shouldContinue","$ifPassed","$caseIndex","then",37,38,"$shouldUseGroup","$rulesGroup","$shouldUseRule","$rule","$top","rootId","$closingBraces1","$closingBraces2","$typeSchema","i2","custom","$ruleValidate","$ruleErrs","$ruleErr","$rDef","$inline","$macro","statements","def_customError","$typeChecked","$isArray","$method",39,"_addRule","ruleGroup","rg",40,"description","definitions","schemaArray","positiveInteger","positiveIntegerDefault0","default","simpleTypes","stringArray","title","exclusiveMinimum","exclusiveMaximum",41,"formatMaximum","formatMinimum","exclusiveFormatMaximum","exclusiveFormatMinimum","constant","contains","switch","if","continue",42,"enableV5","ajv","meta","metaSchema","addMetaSchema","META_SCHEMA_ID","addKeyword","containsMacro","formatLimit","enable","./dotjs/_formatLimit","./dotjs/constant","./dotjs/switch","./refs/json-schema-v5.json",43,"json","JSON","cmp","space","cycles","replacer","node","aobj","bobj","seen","parent","indent","colonSeparator","toJSON","sort","keyValue","","has","jsonify",44,"./lib/parse","./lib/stringify",45,"at","ch","text","escapee","\"","\\","/","message","next","c","hex","uffff","parseInt","white","word","reviver","walk","holder",46,"quote","escapable","lastIndex","partial","mind","gap","rep","apply","\b","\t","\n","\f","\r","SCHEMA_URI_FORMAT_FUNC","SCHEMA_URI_FORMAT","schemaKeyRef","getSchema","valid","_skipValidation","_meta","checkUnique","throwOrLogError","currentUriFormat","errorsText","keyRef","_getSchemaObj","removeSchema","jsonStr","skipValidation","shouldAddSchema","cached","addUsedSchema","callValidate","arguments","compiling","currentRA","currentUD","compileSchema","separator","dataPath","addFormat","addInitialSchemas","optsSchemas","schemas","addInitialFormats","cache","errorDataPath","compileAsync","./async","./cache","./compile","./compile/formats","./compile/resolve","./compile/rules","./compile/schema_obj","./keyword","./refs/json-schema-draft-04.json","./v5"],"mappings":";CAAA,SAAUA,GAAG,GAAoB,gBAAVC,UAAoC,mBAATC,QAAsBA,OAAOD,QAAQD,QAAS,IAAmB,kBAATG,SAAqBA,OAAOC,IAAKD,UAAUH,OAAO,CAAC,GAAIK,EAAkCA,GAAb,mBAATC,QAAwBA,OAA+B,mBAATC,QAAwBA,OAA6B,mBAAPC,MAAsBA,KAAYC,KAAKJ,EAAEK,IAAMV,MAAO,WAAW,GAAIG,QAAOD,OAAOD,OAAQ,OAAO,SAAUU,GAAEC,EAAEC,EAAEC,GAAG,QAASC,GAAEC,EAAEC,GAAG,IAAIJ,EAAEG,GAAG,CAAC,IAAIJ,EAAEI,GAAG,CAAC,GAAIE,GAAkB,kBAATC,UAAqBA,OAAQ,KAAIF,GAAGC,EAAE,MAAOA,GAAEF,GAAE,EAAI,IAAGI,EAAE,MAAOA,GAAEJ,GAAE,EAAI,IAAIhB,GAAE,GAAIqB,OAAM,uBAAuBL,EAAE,IAAK,MAAMhB,GAAEsB,KAAK,mBAAmBtB,EAAE,GAAIuB,GAAEV,EAAEG,IAAIf,WAAYW,GAAEI,GAAG,GAAGQ,KAAKD,EAAEtB,QAAQ,SAASU,GAAG,GAAIE,GAAED,EAAEI,GAAG,GAAGL,EAAG,OAAOI,GAAEF,EAAEA,EAAEF,IAAIY,EAAEA,EAAEtB,QAAQU,EAAEC,EAAEC,EAAEC,GAAG,MAAOD,GAAEG,GAAGf,QAAkD,IAAI,GAA1CmB,GAAkB,kBAATD,UAAqBA,QAAgBH,EAAE,EAAIF,EAAEW,OAAJT,EAAWA,IAAID,EAAED,EAAEE,GAAI,OAAOD,KAAKW,GAAG,SAASP,EAAQjB,EAAOD,IACl0B,SAAWM,IAET,SAASoB,GAgEV,QAASC,GAAMC,GACd,KAAM,IAAIC,YAAWC,EAAOF,IAW7B,QAASG,GAAIC,EAAOC,GAGnB,IAFA,GAAIT,GAASQ,EAAMR,OACfU,KACGV,KACNU,EAAOV,GAAUS,EAAGD,EAAMR,GAE3B,OAAOU,GAaR,QAASC,GAAUC,EAAQH,GAC1B,GAAII,GAAQD,EAAOE,MAAM,KACrBJ,EAAS,EACTG,GAAMb,OAAS,IAGlBU,EAASG,EAAM,GAAK,IACpBD,EAASC,EAAM,IAGhBD,EAASA,EAAOG,QAAQC,EAAiB,IACzC,IAAIC,GAASL,EAAOE,MAAM,KACtBI,EAAUX,EAAIU,EAAQR,GAAIU,KAAK,IACnC,OAAOT,GAASQ,EAgBjB,QAASE,GAAWR,GAMnB,IALA,GAGIS,GACAC,EAJAC,KACAC,EAAU,EACVxB,EAASY,EAAOZ,OAGHA,EAAVwB,GACNH,EAAQT,EAAOa,WAAWD,KACtBH,GAAS,OAAmB,OAATA,GAA6BrB,EAAVwB,GAEzCF,EAAQV,EAAOa,WAAWD,KACF,QAAX,MAARF,GACJC,EAAOG,OAAe,KAARL,IAAkB,KAAe,KAARC,GAAiB,QAIxDC,EAAOG,KAAKL,GACZG,MAGDD,EAAOG,KAAKL,EAGd,OAAOE,GAWR,QAASI,GAAWnB,GACnB,MAAOD,GAAIC,EAAO,SAASa,GAC1B,GAAIE,GAAS,EAOb,OANIF,GAAQ,QACXA,GAAS,MACTE,GAAUK,EAAmBP,IAAU,GAAK,KAAQ,OACpDA,EAAQ,MAAiB,KAARA,GAElBE,GAAUK,EAAmBP,KAE3BF,KAAK,IAYT,QAASU,GAAaC,GACrB,MAAqB,IAAjBA,EAAY,GACRA,EAAY,GAEC,GAAjBA,EAAY,GACRA,EAAY,GAEC,GAAjBA,EAAY,GACRA,EAAY,GAEbC,EAcR,QAASC,GAAaC,EAAOC,GAG5B,MAAOD,GAAQ,GAAK,IAAc,GAARA,KAAwB,GAARC,IAAc,GAQzD,QAASC,GAAMC,EAAOC,EAAWC,GAChC,GAAIC,GAAI,CAGR,KAFAH,EAAQE,EAAYE,EAAMJ,EAAQK,GAAQL,GAAS,EACnDA,GAASI,EAAMJ,EAAQC,GACOD,EAAQM,EAAgBC,GAAQ,EAAGJ,GAAKR,EACrEK,EAAQI,EAAMJ,EAAQM,EAEvB,OAAOF,GAAMD,GAAKG,EAAgB,GAAKN,GAASA,EAAQQ,IAUzD,QAASC,GAAOC,GAEf,GAEIC,GAIAC,EACAC,EACAC,EACAC,EACAC,EACAb,EACAN,EACA9C,EAEAkE,EAfA9B,KACA+B,EAAcR,EAAM9C,OAEpBL,EAAI,EACJP,EAAImE,EACJC,EAAOC,CAqBX,KALAT,EAAQF,EAAMY,YAAYC,GACd,EAARX,IACHA,EAAQ,GAGJC,EAAI,EAAOD,EAAJC,IAAaA,EAEpBH,EAAMrB,WAAWwB,IAAM,KAC1B9C,EAAM,aAEPoB,EAAOG,KAAKoB,EAAMrB,WAAWwB,GAM9B,KAAKC,EAAQF,EAAQ,EAAIA,EAAQ,EAAI,EAAWM,EAARJ,GAAgD,CAOvF,IAAKC,EAAOxD,EAAGyD,EAAI,EAAGb,EAAIR,EAErBmB,GAASI,GACZnD,EAAM,iBAGP8B,EAAQJ,EAAaiB,EAAMrB,WAAWyB,OAElCjB,GAASF,GAAQE,EAAQO,GAAOoB,EAASjE,GAAKyD,KACjDjD,EAAM,YAGPR,GAAKsC,EAAQmB,EACbjE,EAASqE,GAALjB,EAAYsB,EAAQtB,GAAKiB,EAAOb,EAAOA,EAAOJ,EAAIiB,IAE1CrE,EAAR8C,GAf+CM,GAAKR,EAmBxDsB,EAAatB,EAAO5C,EAChBiE,EAAIZ,EAAMoB,EAASP,IACtBlD,EAAM,YAGPiD,GAAKC,CAINN,GAAMxB,EAAOvB,OAAS,EACtBwD,EAAOrB,EAAMxC,EAAIwD,EAAMJ,EAAa,GAARI,GAIxBX,EAAM7C,EAAIoD,GAAOa,EAASxE,GAC7Be,EAAM,YAGPf,GAAKoD,EAAM7C,EAAIoD,GACfpD,GAAKoD,EAGLxB,EAAOuC,OAAOnE,IAAK,EAAGP,GAIvB,MAAOuC,GAAWJ,GAUnB,QAASwC,GAAOjB,GACf,GAAI1D,GACAgD,EACA4B,EACAC,EACAT,EACAP,EACAiB,EACAC,EACA5B,EACApD,EACAiF,EAGAd,EAEAe,EACAhB,EACAiB,EANA/C,IAoBJ,KAXAuB,EAAQ1B,EAAW0B,GAGnBQ,EAAcR,EAAM9C,OAGpBZ,EAAImE,EACJnB,EAAQ,EACRoB,EAAOC,EAGFR,EAAI,EAAOK,EAAJL,IAAmBA,EAC9BmB,EAAetB,EAAMG,GACF,IAAfmB,GACH7C,EAAOG,KAAKE,EAAmBwC,GAejC,KAXAJ,EAAiBC,EAAc1C,EAAOvB,OAMlCiE,GACH1C,EAAOG,KAAKiC,GAIWL,EAAjBU,GAA8B,CAIpC,IAAKE,EAAIN,EAAQX,EAAI,EAAOK,EAAJL,IAAmBA,EAC1CmB,EAAetB,EAAMG,GACjBmB,GAAgBhF,GAAoB8E,EAAfE,IACxBF,EAAIE,EAcN,KARAC,EAAwBL,EAAiB,EACrCE,EAAI9E,EAAIoD,GAAOoB,EAASxB,GAASiC,IACpClE,EAAM,YAGPiC,IAAU8B,EAAI9E,GAAKiF,EACnBjF,EAAI8E,EAECjB,EAAI,EAAOK,EAAJL,IAAmBA,EAO9B,GANAmB,EAAetB,EAAMG,GAEF7D,EAAfgF,KAAsBhC,EAAQwB,GACjCzD,EAAM,YAGHiE,GAAgBhF,EAAG,CAEtB,IAAK+E,EAAI/B,EAAOG,EAAIR,EACnB5C,EAASqE,GAALjB,EAAYsB,EAAQtB,GAAKiB,EAAOb,EAAOA,EAAOJ,EAAIiB,IAC9CrE,EAAJgF,GAFyC5B,GAAKR,EAKlDuC,EAAUH,EAAIhF,EACdkE,EAAatB,EAAO5C,EACpBoC,EAAOG,KACNE,EAAmBI,EAAa7C,EAAImF,EAAUjB,EAAY,KAE3Dc,EAAI3B,EAAM8B,EAAUjB,EAGrB9B,GAAOG,KAAKE,EAAmBI,EAAamC,EAAG,KAC/CX,EAAOrB,EAAMC,EAAOiC,EAAuBL,GAAkBC,GAC7D7B,EAAQ,IACN4B,IAIF5B,IACAhD,EAGH,MAAOmC,GAAOJ,KAAK,IAcpB,QAASoD,GAAUzB,GAClB,MAAOnC,GAAUmC,EAAO,SAASlC,GAChC,MAAO4D,GAAcC,KAAK7D,GACvBiC,EAAOjC,EAAO8D,MAAM,GAAGC,eACvB/D,IAeL,QAASgE,GAAQ9B,GAChB,MAAOnC,GAAUmC,EAAO,SAASlC,GAChC,MAAOiE,GAAcJ,KAAK7D,GACvB,OAASmD,EAAOnD,GAChBA,IAvdL,GAAIkE,GAAgC,gBAAXtG,IAAuBA,IAC9CA,EAAQuG,UAAYvG,EAClBwG,EAA8B,gBAAVvG,IAAsBA,IAC5CA,EAAOsG,UAAYtG,EACjBwG,EAA8B,gBAAVnG,IAAsBA,GAE7CmG,EAAWnG,SAAWmG,GACtBA,EAAWpG,SAAWoG,GACtBA,EAAWlG,OAASkG,KAEpB/E,EAAO+E,EAQR,IAAIC,GAiCJC,EA9BAvB,EAAS,WAGT7B,EAAO,GACP8B,EAAO,EACPlB,EAAO,GACPC,EAAO,GACPH,EAAO,IACPgB,EAAc,GACdF,EAAW,IACXI,EAAY,IAGZa,EAAgB,QAChBK,EAAgB,eAChB7D,EAAkB,4BAGlBV,GACC8E,SAAY,kDACZC,YAAa,iDACbC,gBAAiB,iBAIlB5C,EAAgBX,EAAO8B,EACvBrB,EAAQ+C,KAAK/C,MACbZ,EAAqB4D,OAAOC,YAyc5B,IA3BAP,GAMCQ,QAAW,QAQXC,MACC9C,OAAUzB,EACV2C,OAAUpC,GAEXkB,OAAUA,EACVkB,OAAUA,EACVa,QAAWA,EACXL,UAAaA,GAOI,kBAAV7F,SACc,gBAAdA,QAAOC,KACdD,OAAOC,IAEPD,OAAO,WAAY,WAClB,MAAOwG,SAEF,IAAIJ,GAAeE,EACzB,GAAIvG,EAAOD,SAAWsG,EAErBE,EAAWxG,QAAU0G,MAGrB,KAAKC,IAAOD,GACXA,EAASU,eAAeT,KAASL,EAAYK,GAAOD,EAASC,QAK/DjF,GAAKgF,SAAWA,GAGhBlG,QAECe,KAAKf,KAAuB,mBAAXF,QAAyBA,OAAyB,mBAATC,MAAuBA,KAAyB,mBAAXF,QAAyBA,gBACrHgH,GAAG,SAASnG,EAAQjB,EAAOD,GAsBjC,YAKA,SAASoH,GAAeE,EAAKC,GAC3B,MAAOC,QAAOC,UAAUL,eAAe7F,KAAK+F,EAAKC,GAGnDtH,EAAOD,QAAU,SAAS0H,EAAIC,EAAKC,EAAIC,GACrCF,EAAMA,GAAO,IACbC,EAAKA,GAAM,GACX,IAAIN,KAEJ,IAAkB,gBAAPI,IAAiC,IAAdA,EAAGlG,OAC/B,MAAO8F,EAGT,IAAIQ,GAAS,KACbJ,GAAKA,EAAGpF,MAAMqF,EAEd,IAAII,GAAU,GACVF,IAAsC,gBAApBA,GAAQE,UAC5BA,EAAUF,EAAQE,QAGpB,IAAIC,GAAMN,EAAGlG,MAETuG,GAAU,GAAKC,EAAMD,IACvBC,EAAMD,EAGR,KAAK,GAAI5G,GAAI,EAAO6G,EAAJ7G,IAAWA,EAAG,CAC5B,GAEI8G,GAAMC,EAAMnE,EAAGoE,EAFfC,EAAIV,EAAGvG,GAAGoB,QAAQuF,EAAQ,OAC1BO,EAAMD,EAAEE,QAAQV,EAGhBS,IAAO,GACTJ,EAAOG,EAAEG,OAAO,EAAGF,GACnBH,EAAOE,EAAEG,OAAOF,EAAM,KAEtBJ,EAAOG,EACPF,EAAO,IAGTnE,EAAIyE,mBAAmBP,GACvBE,EAAIK,mBAAmBN,GAElBd,EAAeE,EAAKvD,GAEd0E,EAAQnB,EAAIvD,IACrBuD,EAAIvD,GAAGb,KAAKiF,GAEZb,EAAIvD,IAAMuD,EAAIvD,GAAIoE,GAJlBb,EAAIvD,GAAKoE,EAQb,MAAOb,GAGT,IAAImB,GAAUC,MAAMD,SAAW,SAAUE,GACvC,MAA8C,mBAAvCnB,OAAOC,UAAUmB,SAASrH,KAAKoH,SAGlCE,GAAG,SAAS3H,EAAQjB,EAAOD,GAsBjC,YAgDA,SAAS+B,GAAK4G,EAAI5I,GAChB,GAAI4I,EAAG5G,IAAK,MAAO4G,GAAG5G,IAAIhC,EAE1B,KAAK,GADD+I,MACK3H,EAAI,EAAOwH,EAAGnH,OAAPL,EAAeA,IAC7B2H,EAAI5F,KAAKnD,EAAE4I,EAAGxH,GAAIA,GAEpB,OAAO2H,GApDT,GAAIC,GAAqB,SAASZ,GAChC,aAAeA,IACb,IAAK,SACH,MAAOA,EAET,KAAK,UACH,MAAOA,GAAI,OAAS,OAEtB,KAAK,SACH,MAAOa,UAASb,GAAKA,EAAI,EAE3B,SACE,MAAO,IAIblI,GAAOD,QAAU,SAASsH,EAAKK,EAAKC,EAAIqB,GAOtC,MANAtB,GAAMA,GAAO,IACbC,EAAKA,GAAM,IACC,OAARN,IACFA,EAAM4B,QAGW,gBAAR5B,GACFvF,EAAIoH,EAAW7B,GAAM,SAASvD,GACnC,GAAIqF,GAAKC,mBAAmBN,EAAmBhF,IAAM6D,CACrD,OAAIa,GAAQnB,EAAIvD,IACPhC,EAAIuF,EAAIvD,GAAI,SAASoE,GAC1B,MAAOiB,GAAKC,mBAAmBN,EAAmBZ,MACjDxF,KAAKgF,GAEDyB,EAAKC,mBAAmBN,EAAmBzB,EAAIvD,OAEvDpB,KAAKgF,GAILsB,EACEI,mBAAmBN,EAAmBE,IAASrB,EAC/CyB,mBAAmBN,EAAmBzB,IAF3B,GAKpB,IAAImB,GAAUC,MAAMD,SAAW,SAAUE,GACvC,MAA8C,mBAAvCnB,OAAOC,UAAUmB,SAASrH,KAAKoH,IAYpCQ,EAAa3B,OAAO8B,MAAQ,SAAUhC,GACxC,GAAIwB,KACJ,KAAK,GAAInC,KAAOW,GACVE,OAAOC,UAAUL,eAAe7F,KAAK+F,EAAKX,IAAMmC,EAAI5F,KAAKyD,EAE/D,OAAOmC,SAGHS,GAAG,SAASrI,EAAQjB,EAAOD,GACjC,YAEAA,GAAQqE,OAASrE,EAAQwJ,MAAQtI,EAAQ,YACzClB,EAAQuF,OAASvF,EAAQyJ,UAAYvI,EAAQ,cAE1CwI,WAAW,EAAEC,WAAW,IAAIC,GAAG,SAAS1I,EAAQjB,EAAOD,GAsB1D,YAYA,SAAS6J,KACPrJ,KAAKsJ,SAAW,KAChBtJ,KAAKuJ,QAAU,KACfvJ,KAAKwJ,KAAO,KACZxJ,KAAKyJ,KAAO,KACZzJ,KAAK0J,KAAO,KACZ1J,KAAK2J,SAAW,KAChB3J,KAAK4J,KAAO,KACZ5J,KAAK6J,OAAS,KACd7J,KAAK8J,MAAQ,KACb9J,KAAK+J,SAAW,KAChB/J,KAAKgK,KAAO,KACZhK,KAAKiK,KAAO,KAwDd,QAASC,GAASC,EAAKC,EAAkBC,GACvC,GAAIF,GAAOG,EAAKC,SAASJ,IAAQA,YAAed,GAAK,MAAOc,EAE5D,IAAI3J,GAAI,GAAI6I,EAEZ,OADA7I,GAAEwI,MAAMmB,EAAKC,EAAkBC,GACxB7J,EAyQT,QAASgK,GAAU1D,GAMjB,MADIwD,GAAKG,SAAS3D,KAAMA,EAAMoD,EAASpD,IACjCA,YAAeuC,GACdvC,EAAI4D,SADuBrB,EAAIpC,UAAUyD,OAAO3J,KAAK+F,GA4D9D,QAAS6D,GAAWC,EAAQC,GAC1B,MAAOX,GAASU,GAAQ,GAAO,GAAME,QAAQD,GAO/C,QAASE,GAAiBH,EAAQC,GAChC,MAAKD,GACEV,EAASU,GAAQ,GAAO,GAAMI,cAAcH,GAD/BA,EAvatB,GAAI3E,GAAWxF,EAAQ,YACnB4J,EAAO5J,EAAQ,SAEnBlB,GAAQwJ,MAAQkB,EAChB1K,EAAQsL,QAAUH,EAClBnL,EAAQwL,cAAgBD,EACxBvL,EAAQkL,OAASF,EAEjBhL,EAAQ6J,IAAMA,CAqBd,IAAI4B,GAAkB,oBAClBC,EAAc,WAGdC,EAAoB,qCAIpBC,GAAU,IAAK,IAAK,IAAK,IAAK,IAAK,KAAM,KAAM,KAG/CC,GAAU,IAAK,IAAK,IAAK,KAAM,IAAK,KAAKC,OAAOF,GAGhDG,GAAc,KAAMD,OAAOD,GAK3BG,GAAgB,IAAK,IAAK,IAAK,IAAK,KAAKF,OAAOC,GAChDE,GAAmB,IAAK,IAAK,KAC7BC,EAAiB,IACjBC,EAAsB,yBACtBC,EAAoB,+BAEpBC,GACEC,YAAc,EACdC,eAAe,GAGjBC,GACEF,YAAc,EACdC,eAAe,GAGjBE,GACEC,MAAQ,EACRC,OAAS,EACTC,KAAO,EACPC,QAAU,EACVC,MAAQ,EACRC,SAAS,EACTC,UAAU,EACVC,QAAQ,EACRC,WAAW,EACXC,SAAS,GAEXC,EAAclM,EAAQ,cAU1B2I,GAAIpC,UAAU+B,MAAQ,SAASmB,EAAKC,EAAkBC,GACpD,IAAKC,EAAKG,SAASN,GACjB,KAAM,IAAI0C,WAAU,+CAAkD1C,GAMxE,IAAI2C,GAAa3C,EAAIrC,QAAQ,KACzBiF,EACoB,KAAfD,GAAqBA,EAAa3C,EAAIrC,QAAQ,KAAQ,IAAM,IACjEkF,EAAS7C,EAAIrI,MAAMiL,GACnBE,EAAa,KACjBD,GAAO,GAAKA,EAAO,GAAGjL,QAAQkL,EAAY,KAC1C9C,EAAM6C,EAAO7K,KAAK4K,EAElB,IAAIG,GAAO/C,CAMX,IAFA+C,EAAOA,EAAKC,QAEP9C,GAA+C,IAA1BF,EAAIrI,MAAM,KAAKd,OAAc,CAErD,GAAIoM,GAAajC,EAAkBkC,KAAKH,EACxC,IAAIE,EAeF,MAdApN,MAAKgK,KAAOkD,EACZlN,KAAKiK,KAAOiD,EACZlN,KAAK+J,SAAWqD,EAAW,GACvBA,EAAW,IACbpN,KAAK6J,OAASuD,EAAW,GAEvBpN,KAAK8J,MADHM,EACWwC,EAAY5D,MAAMhJ,KAAK6J,OAAO9B,OAAO,IAErC/H,KAAK6J,OAAO9B,OAAO,IAEzBqC,IACTpK,KAAK6J,OAAS,GACd7J,KAAK8J,UAEA9J,KAIX,GAAIsN,GAAQrC,EAAgBoC,KAAKH,EACjC,IAAII,EAAO,CACTA,EAAQA,EAAM,EACd,IAAIC,GAAaD,EAAM3H,aACvB3F,MAAKsJ,SAAWiE,EAChBL,EAAOA,EAAKnF,OAAOuF,EAAMtM,QAO3B,GAAIqJ,GAAqBiD,GAASJ,EAAKM,MAAM,wBAAyB,CACpE,GAAIjE,GAAgC,OAAtB2D,EAAKnF,OAAO,EAAG,IACzBwB,GAAa+D,GAAStB,EAAiBsB,KACzCJ,EAAOA,EAAKnF,OAAO,GACnB/H,KAAKuJ,SAAU,GAInB,IAAKyC,EAAiBsB,KACjB/D,GAAY+D,IAAUrB,EAAgBqB,IAAU,CAmBnD,IAAK,GADDG,GAAU,GACL9M,EAAI,EAAO8K,EAAgBzK,OAApBL,EAA4BA,IAAK,CAC/C,GAAI+M,GAAMR,EAAKpF,QAAQ2D,EAAgB9K,GAC3B,MAAR+M,IAA2B,KAAZD,GAAwBA,EAANC,KACnCD,EAAUC,GAKd,GAAIlE,GAAMmE,CAGRA,GAFc,KAAZF,EAEOP,EAAKxI,YAAY,KAIjBwI,EAAKxI,YAAY,IAAK+I,GAKlB,KAAXE,IACFnE,EAAO0D,EAAKxH,MAAM,EAAGiI,GACrBT,EAAOA,EAAKxH,MAAMiI,EAAS,GAC3B3N,KAAKwJ,KAAOxB,mBAAmBwB,IAIjCiE,EAAU,EACV,KAAK,GAAI9M,GAAI,EAAO6K,EAAaxK,OAAjBL,EAAyBA,IAAK,CAC5C,GAAI+M,GAAMR,EAAKpF,QAAQ0D,EAAa7K,GACxB,MAAR+M,IAA2B,KAAZD,GAAwBA,EAANC,KACnCD,EAAUC,GAGE,KAAZD,IACFA,EAAUP,EAAKlM,QAEjBhB,KAAKyJ,KAAOyD,EAAKxH,MAAM,EAAG+H,GAC1BP,EAAOA,EAAKxH,MAAM+H,GAGlBzN,KAAK4N,YAIL5N,KAAK2J,SAAW3J,KAAK2J,UAAY,EAIjC,IAAIkE,GAAoC,MAArB7N,KAAK2J,SAAS,IACe,MAA5C3J,KAAK2J,SAAS3J,KAAK2J,SAAS3I,OAAS,EAGzC,KAAK6M,EAEH,IAAK,GADDC,GAAY9N,KAAK2J,SAAS7H,MAAM,MAC3BnB,EAAI,EAAGG,EAAIgN,EAAU9M,OAAYF,EAAJH,EAAOA,IAAK,CAChD,GAAIoN,GAAOD,EAAUnN,EACrB,IAAKoN,IACAA,EAAKP,MAAM7B,GAAsB,CAEpC,IAAK,GADDqC,GAAU,GACL/J,EAAI,EAAGV,EAAIwK,EAAK/M,OAAYuC,EAAJU,EAAOA,IAKpC+J,GAJED,EAAKtL,WAAWwB,GAAK,IAIZ,IAEA8J,EAAK9J,EAIpB,KAAK+J,EAAQR,MAAM7B,GAAsB,CACvC,GAAIsC,GAAaH,EAAUpI,MAAM,EAAG/E,GAChCuN,EAAUJ,EAAUpI,MAAM/E,EAAI,GAC9BwN,EAAMJ,EAAKP,MAAM5B,EACjBuC,KACFF,EAAWvL,KAAKyL,EAAI,IACpBD,EAAQE,QAAQD,EAAI,KAElBD,EAAQlN,SACVkM,EAAO,IAAMgB,EAAQ/L,KAAK,KAAO+K,GAEnClN,KAAK2J,SAAWsE,EAAW9L,KAAK,IAChC,SAONnC,KAAK2J,SADH3J,KAAK2J,SAAS3I,OAAS0K,EACT,GAGA1L,KAAK2J,SAAShE,cAG3BkI,IAKH7N,KAAK2J,SAAWzD,EAASN,QAAQ5F,KAAK2J,UAGxC,IAAI0E,GAAIrO,KAAK0J,KAAO,IAAM1J,KAAK0J,KAAO,GAClC4E,EAAItO,KAAK2J,UAAY,EACzB3J,MAAKyJ,KAAO6E,EAAID,EAChBrO,KAAKiK,MAAQjK,KAAKyJ,KAIdoE,IACF7N,KAAK2J,SAAW3J,KAAK2J,SAAS5B,OAAO,EAAG/H,KAAK2J,SAAS3I,OAAS,GAC/C,MAAZkM,EAAK,KACPA,EAAO,IAAMA,IAOnB,IAAKrB,EAAe0B,GAKlB,IAAK,GAAI5M,GAAI,EAAGG,EAAIyK,EAAWvK,OAAYF,EAAJH,EAAOA,IAAK,CACjD,GAAI4N,GAAKhD,EAAW5K,EACpB,IAAyB,KAArBuM,EAAKpF,QAAQyG,GAAjB,CAEA,GAAIC,GAAM3F,mBAAmB0F,EACzBC,KAAQD,IACVC,EAAMC,OAAOF,IAEfrB,EAAOA,EAAKpL,MAAMyM,GAAIpM,KAAKqM,IAM/B,GAAI5E,GAAOsD,EAAKpF,QAAQ,IACX,MAAT8B,IAEF5J,KAAK4J,KAAOsD,EAAKnF,OAAO6B,GACxBsD,EAAOA,EAAKxH,MAAM,EAAGkE,GAEvB,IAAI8E,GAAKxB,EAAKpF,QAAQ,IAoBtB,IAnBW,KAAP4G,GACF1O,KAAK6J,OAASqD,EAAKnF,OAAO2G,GAC1B1O,KAAK8J,MAAQoD,EAAKnF,OAAO2G,EAAK,GAC1BtE,IACFpK,KAAK8J,MAAQ8C,EAAY5D,MAAMhJ,KAAK8J,QAEtCoD,EAAOA,EAAKxH,MAAM,EAAGgJ,IACZtE,IAETpK,KAAK6J,OAAS,GACd7J,KAAK8J,UAEHoD,IAAMlN,KAAK+J,SAAWmD,GACtBjB,EAAgBsB,IAChBvN,KAAK2J,WAAa3J,KAAK+J,WACzB/J,KAAK+J,SAAW,KAId/J,KAAK+J,UAAY/J,KAAK6J,OAAQ,CAChC,GAAIwE,GAAIrO,KAAK+J,UAAY,GACrBzJ,EAAIN,KAAK6J,QAAU,EACvB7J,MAAKgK,KAAOqE,EAAI/N,EAKlB,MADAN,MAAKiK,KAAOjK,KAAK0K,SACV1K,MAcTqJ,EAAIpC,UAAUyD,OAAS,WACrB,GAAIlB,GAAOxJ,KAAKwJ,MAAQ,EACpBA,KACFA,EAAOX,mBAAmBW,GAC1BA,EAAOA,EAAKzH,QAAQ,OAAQ,KAC5ByH,GAAQ,IAGV,IAAIF,GAAWtJ,KAAKsJ,UAAY,GAC5BS,EAAW/J,KAAK+J,UAAY,GAC5BH,EAAO5J,KAAK4J,MAAQ,GACpBH,GAAO,EACPK,EAAQ,EAER9J,MAAKyJ,KACPA,EAAOD,EAAOxJ,KAAKyJ,KACVzJ,KAAK2J,WACdF,EAAOD,GAAuC,KAA/BxJ,KAAK2J,SAAS7B,QAAQ,KACjC9H,KAAK2J,SACL,IAAM3J,KAAK2J,SAAW,KACtB3J,KAAK0J,OACPD,GAAQ,IAAMzJ,KAAK0J,OAInB1J,KAAK8J,OACLQ,EAAKC,SAASvK,KAAK8J,QACnB9C,OAAO8B,KAAK9I,KAAK8J,OAAO9I,SAC1B8I,EAAQ8C,EAAY3D,UAAUjJ,KAAK8J,OAGrC,IAAID,GAAS7J,KAAK6J,QAAWC,GAAU,IAAMA,GAAW,EAsBxD,OApBIR,IAAoC,MAAxBA,EAASvB,OAAO,MAAauB,GAAY,KAIrDtJ,KAAKuJ,WACHD,GAAY2C,EAAgB3C,KAAcG,KAAS,GACvDA,EAAO,MAAQA,GAAQ,IACnBM,GAAmC,MAAvBA,EAAS4E,OAAO,KAAY5E,EAAW,IAAMA,IACnDN,IACVA,EAAO,IAGLG,GAA2B,MAAnBA,EAAK+E,OAAO,KAAY/E,EAAO,IAAMA,GAC7CC,GAA+B,MAArBA,EAAO8E,OAAO,KAAY9E,EAAS,IAAMA,GAEvDE,EAAWA,EAAShI,QAAQ,QAAS,SAASyL,GAC5C,MAAO3E,oBAAmB2E,KAE5B3D,EAASA,EAAO9H,QAAQ,IAAK,OAEtBuH,EAAWG,EAAOM,EAAWF,EAASD,GAO/CP,EAAIpC,UAAU6D,QAAU,SAASD,GAC/B,MAAO7K,MAAKgL,cAAcd,EAASW,GAAU,GAAO,IAAOH,UAQ7DrB,EAAIpC,UAAU+D,cAAgB,SAASH,GACrC,GAAIP,EAAKG,SAASI,GAAW,CAC3B,GAAI+D,GAAM,GAAIvF,EACduF,GAAI5F,MAAM6B,GAAU,GAAO,GAC3BA,EAAW+D,EAKb,IAAK,GAFDlN,GAAS,GAAI2H,GACbwF,EAAQ7H,OAAO8B,KAAK9I,MACf8O,EAAK,EAAQD,EAAM7N,OAAX8N,EAAmBA,IAAM,CACxC,GAAIC,GAAOF,EAAMC,EACjBpN,GAAOqN,GAAQ/O,KAAK+O,GAQtB,GAHArN,EAAOkI,KAAOiB,EAASjB,KAGD,KAAlBiB,EAASZ,KAEX,MADAvI,GAAOuI,KAAOvI,EAAOgJ,SACdhJ,CAIT,IAAImJ,EAAStB,UAAYsB,EAASvB,SAAU,CAG1C,IAAK,GADD0F,GAAQhI,OAAO8B,KAAK+B,GACfoE,EAAK,EAAQD,EAAMhO,OAAXiO,EAAmBA,IAAM,CACxC,GAAIC,GAAOF,EAAMC,EACJ,cAATC,IACFxN,EAAOwN,GAAQrE,EAASqE,IAU5B,MANIjD,GAAgBvK,EAAO4H,WACvB5H,EAAOiI,WAAajI,EAAOqI,WAC7BrI,EAAOsI,KAAOtI,EAAOqI,SAAW,KAGlCrI,EAAOuI,KAAOvI,EAAOgJ,SACdhJ,EAGT,GAAImJ,EAASvB,UAAYuB,EAASvB,WAAa5H,EAAO4H,SAAU,CAS9D,IAAK2C,EAAgBpB,EAASvB,UAAW,CAEvC,IAAK,GADDR,GAAO9B,OAAO8B,KAAK+B,GACdlD,EAAI,EAAOmB,EAAK9H,OAAT2G,EAAiBA,IAAK,CACpC,GAAIpE,GAAIuF,EAAKnB,EACbjG,GAAO6B,GAAKsH,EAAStH,GAGvB,MADA7B,GAAOuI,KAAOvI,EAAOgJ,SACdhJ,EAIT,GADAA,EAAO4H,SAAWuB,EAASvB,SACtBuB,EAASpB,MAASuC,EAAiBnB,EAASvB,UAS/C5H,EAAOqI,SAAWc,EAASd,aAT+B,CAE1D,IADA,GAAIoF,IAAWtE,EAASd,UAAY,IAAIjI,MAAM,KACvCqN,EAAQnO,UAAY6J,EAASpB,KAAO0F,EAAQC,WAC9CvE,EAASpB,OAAMoB,EAASpB,KAAO,IAC/BoB,EAASlB,WAAUkB,EAASlB,SAAW,IACzB,KAAfwF,EAAQ,IAAWA,EAAQf,QAAQ,IAClB,EAAjBe,EAAQnO,QAAYmO,EAAQf,QAAQ,IACxC1M,EAAOqI,SAAWoF,EAAQhN,KAAK,KAWjC,GAPAT,EAAOmI,OAASgB,EAAShB,OACzBnI,EAAOoI,MAAQe,EAASf,MACxBpI,EAAO+H,KAAOoB,EAASpB,MAAQ,GAC/B/H,EAAO8H,KAAOqB,EAASrB,KACvB9H,EAAOiI,SAAWkB,EAASlB,UAAYkB,EAASpB,KAChD/H,EAAOgI,KAAOmB,EAASnB,KAEnBhI,EAAOqI,UAAYrI,EAAOmI,OAAQ,CACpC,GAAIwE,GAAI3M,EAAOqI,UAAY,GACvBzJ,EAAIoB,EAAOmI,QAAU,EACzBnI,GAAOsI,KAAOqE,EAAI/N,EAIpB,MAFAoB,GAAO6H,QAAU7H,EAAO6H,SAAWsB,EAAStB,QAC5C7H,EAAOuI,KAAOvI,EAAOgJ,SACdhJ,EAGT,GAAI2N,GAAe3N,EAAOqI,UAA0C,MAA9BrI,EAAOqI,SAAS4E,OAAO,GACzDW,EACIzE,EAASpB,MACToB,EAASd,UAA4C,MAAhCc,EAASd,SAAS4E,OAAO,GAElDY,EAAcD,GAAYD,GACX3N,EAAO+H,MAAQoB,EAASd,SACvCyF,EAAgBD,EAChBE,EAAU/N,EAAOqI,UAAYrI,EAAOqI,SAASjI,MAAM,SACnDqN,EAAUtE,EAASd,UAAYc,EAASd,SAASjI,MAAM,SACvD4N,EAAYhO,EAAO4H,WAAa2C,EAAgBvK,EAAO4H,SA2B3D,IApBIoG,IACFhO,EAAOiI,SAAW,GAClBjI,EAAOgI,KAAO,KACVhI,EAAO+H,OACU,KAAfgG,EAAQ,GAAWA,EAAQ,GAAK/N,EAAO+H,KACtCgG,EAAQrB,QAAQ1M,EAAO+H,OAE9B/H,EAAO+H,KAAO,GACVoB,EAASvB,WACXuB,EAASlB,SAAW,KACpBkB,EAASnB,KAAO,KACZmB,EAASpB,OACQ,KAAf0F,EAAQ,GAAWA,EAAQ,GAAKtE,EAASpB,KACxC0F,EAAQf,QAAQvD,EAASpB,OAEhCoB,EAASpB,KAAO,MAElB8F,EAAaA,IAA8B,KAAfJ,EAAQ,IAA4B,KAAfM,EAAQ,KAGvDH,EAEF5N,EAAO+H,KAAQoB,EAASpB,MAA0B,KAAlBoB,EAASpB,KAC3BoB,EAASpB,KAAO/H,EAAO+H,KACrC/H,EAAOiI,SAAYkB,EAASlB,UAAkC,KAAtBkB,EAASlB,SAC/BkB,EAASlB,SAAWjI,EAAOiI,SAC7CjI,EAAOmI,OAASgB,EAAShB,OACzBnI,EAAOoI,MAAQe,EAASf,MACxB2F,EAAUN,MAEL,IAAIA,EAAQnO,OAGZyO,IAASA,MACdA,EAAQE,MACRF,EAAUA,EAAQnE,OAAO6D,GACzBzN,EAAOmI,OAASgB,EAAShB,OACzBnI,EAAOoI,MAAQe,EAASf,UACnB,KAAKQ,EAAKsF,kBAAkB/E,EAAShB,QAAS,CAInD,GAAI6F,EAAW,CACbhO,EAAOiI,SAAWjI,EAAO+H,KAAOgG,EAAQL,OAIxC,IAAIS,GAAanO,EAAO+H,MAAQ/H,EAAO+H,KAAK3B,QAAQ,KAAO,EAC1CpG,EAAO+H,KAAK3H,MAAM,MAAO,CACtC+N,KACFnO,EAAO8H,KAAOqG,EAAWT,QACzB1N,EAAO+H,KAAO/H,EAAOiI,SAAWkG,EAAWT,SAW/C,MARA1N,GAAOmI,OAASgB,EAAShB,OACzBnI,EAAOoI,MAAQe,EAASf,MAEnBQ,EAAKwF,OAAOpO,EAAOqI,WAAcO,EAAKwF,OAAOpO,EAAOmI,UACvDnI,EAAOsI,MAAQtI,EAAOqI,SAAWrI,EAAOqI,SAAW,KACpCrI,EAAOmI,OAASnI,EAAOmI,OAAS,KAEjDnI,EAAOuI,KAAOvI,EAAOgJ,SACdhJ,EAGT,IAAK+N,EAAQzO,OAWX,MARAU,GAAOqI,SAAW,KAGhBrI,EAAOsI,KADLtI,EAAOmI,OACK,IAAMnI,EAAOmI,OAEb,KAEhBnI,EAAOuI,KAAOvI,EAAOgJ,SACdhJ,CAcT,KAAK,GARDqO,GAAON,EAAQ/J,MAAM,IAAI,GACzBsK,GACCtO,EAAO+H,MAAQoB,EAASpB,MAAQgG,EAAQzO,OAAS,KACxC,MAAT+O,GAAyB,OAATA,IAA2B,KAATA,EAInCE,EAAK,EACAtP,EAAI8O,EAAQzO,OAAQL,GAAK,EAAGA,IACnCoP,EAAON,EAAQ9O,GACF,MAAToP,EACFN,EAAQ3K,OAAOnE,EAAG,GACA,OAAToP,GACTN,EAAQ3K,OAAOnE,EAAG,GAClBsP,KACSA,IACTR,EAAQ3K,OAAOnE,EAAG,GAClBsP,IAKJ,KAAKV,IAAeC,EAClB,KAAOS,IAAMA,EACXR,EAAQrB,QAAQ,OAIhBmB,GAA6B,KAAfE,EAAQ,IACpBA,EAAQ,IAA+B,MAAzBA,EAAQ,GAAGd,OAAO,IACpCc,EAAQrB,QAAQ,IAGd4B,GAAsD,MAAjCP,EAAQtN,KAAK,KAAK4F,OAAO,KAChD0H,EAAQ/M,KAAK,GAGf,IAAIwN,GAA4B,KAAfT,EAAQ,IACpBA,EAAQ,IAA+B,MAAzBA,EAAQ,GAAGd,OAAO,EAGrC,IAAIe,EAAW,CACbhO,EAAOiI,SAAWjI,EAAO+H,KAAOyG,EAAa,GACbT,EAAQzO,OAASyO,EAAQL,QAAU,EAInE,IAAIS,GAAanO,EAAO+H,MAAQ/H,EAAO+H,KAAK3B,QAAQ,KAAO,EAC1CpG,EAAO+H,KAAK3H,MAAM,MAAO,CACtC+N,KACFnO,EAAO8H,KAAOqG,EAAWT,QACzB1N,EAAO+H,KAAO/H,EAAOiI,SAAWkG,EAAWT,SAyB/C,MArBAG,GAAaA,GAAe7N,EAAO+H,MAAQgG,EAAQzO,OAE/CuO,IAAeW,GACjBT,EAAQrB,QAAQ,IAGbqB,EAAQzO,OAIXU,EAAOqI,SAAW0F,EAAQtN,KAAK,MAH/BT,EAAOqI,SAAW,KAClBrI,EAAOsI,KAAO,MAMXM,EAAKwF,OAAOpO,EAAOqI,WAAcO,EAAKwF,OAAOpO,EAAOmI,UACvDnI,EAAOsI,MAAQtI,EAAOqI,SAAWrI,EAAOqI,SAAW,KACpCrI,EAAOmI,OAASnI,EAAOmI,OAAS,KAEjDnI,EAAO8H,KAAOqB,EAASrB,MAAQ9H,EAAO8H,KACtC9H,EAAO6H,QAAU7H,EAAO6H,SAAWsB,EAAStB,QAC5C7H,EAAOuI,KAAOvI,EAAOgJ,SACdhJ,GAGT2H,EAAIpC,UAAU2G,UAAY,WACxB,GAAInE,GAAOzJ,KAAKyJ,KACZC,EAAOwB,EAAYmC,KAAK5D,EACxBC,KACFA,EAAOA,EAAK,GACC,MAATA,IACF1J,KAAK0J,KAAOA,EAAK3B,OAAO,IAE1B0B,EAAOA,EAAK1B,OAAO,EAAG0B,EAAKzI,OAAS0I,EAAK1I,SAEvCyI,IAAMzJ,KAAK2J,SAAWF,MAGzB0G,SAAS,EAAEjK,SAAW,EAAE0G,YAAc,IAAIwD,GAAG,SAAS1P,EAAQjB,EAAOD,GACxE,YAEAC,GAAOD,SACLiL,SAAU,SAAS4F,GACjB,MAAuB,gBAAV,IAEf9F,SAAU,SAAS8F,GACjB,MAAuB,gBAAV,IAA8B,OAARA,GAErCP,OAAQ,SAASO,GACf,MAAe,QAARA,GAETT,kBAAmB,SAASS,GAC1B,MAAc,OAAPA,SAILC,GAAG,SAAS5P,EAAQjB,EAAOD,GACjC,YAQAC,GAAOD,QAAU,SAAsB+Q,EAAQC,GAkB7C,QAASC,GAAcF,EAAQC,EAAUE,GAUvC,QAASC,GAAkBzQ,GAuBzB,QAAS0Q,GAAaC,EAAKC,GACzB,GAAID,EAAKL,EAASK,OACb,CACH,IAAM9Q,EAAKgR,MAAMC,KAAQjR,EAAKkR,SAASD,GACrC,IACEjR,EAAKmR,UAAUJ,EAAKE,GACpB,MAAM9Q,GAEN,WADAsQ,GAAStQ,GAIbuQ,EAAcF,EAAQC,IAjC1B,GAAIQ,GAAM9Q,EAAEiR,aACZ,IAAIpR,EAAKgR,MAAMC,IAAQjR,EAAKkR,SAASD,GACnC,MAAOR,GAAS,GAAI5P,OAAM,UAAYoQ,EAAM,iBAAmB9Q,EAAEkR,WAAa,sBAChF,IAAIC,GAAatR,EAAKuR,gBAAgBN,EAClCK,GACuB,kBAAdA,GACTtR,EAAKuR,gBAAgBN,IAAQK,EAAYT,GAEzCS,EAAWA,EAAWrQ,QAAU4P,GAElC7Q,EAAKuR,gBAAgBN,GAAOJ,EAC5B7Q,EAAKwR,KAAKC,WAAWR,EAAK,SAAUH,EAAKC,GACvC,GAAIO,GAAatR,EAAKuR,gBAAgBN,EAEtC,UADOjR,GAAKuR,gBAAgBN,GACH,kBAAdK,GACTA,EAAWR,EAAKC,OAEhB,KAAK,GAAInQ,GAAE,EAAK0Q,EAAWrQ,OAAbL,EAAqBA,IACjC0Q,EAAW1Q,GAAGkQ,EAAKC,MAoB7B,QAASW,GAAcZ,EAAKa,GACtBhB,EAAWiB,WAAW,WAAanB,EAASK,EAAKa,KAChDlB,EAASK,EAAKa,GAlDrB,GAAIA,EACJ,KAAMA,EAAW3R,EAAK6R,QAAQrB,GAC9B,MAAMrQ,GAGJ,YAFIA,EAAEiR,cAAeR,EAAkBzQ,GAClCuR,EAAcvR,IAGrBuR,EAAc,KAAMC,GAzBtB,GAAIG,GACA9R,EAAOC,IACX,KACE6R,EAAY7R,KAAK8R,WAAWvB,GAC5B,MAAMrQ,GAEN,WADAyR,YAAW,WAAanB,EAAStQ,KAGnC,GAAI2R,EAAUH,SACZC,WAAW,WAAanB,EAAS,KAAMqB,EAAUH,gBAC9C,CACH,GAAmC,kBAAxB1R,MAAKuR,KAAKC,WACnB,KAAM,IAAI5Q,OAAM,0CAClB6P,GAAcF,EAAQC,GAAU,UA4D9BuB,GAAG,SAASrR,EAAQjB,EAAOD,GACjC,YAGA,IAAIwS,GAAQvS,EAAOD,QAAU,WACzBQ,KAAKiS,UAITD,GAAM/K,UAAUiL,IAAM,SAAmB/L,EAAK9D,GAC1CrC,KAAKiS,OAAO9L,GAAO9D,GAIvB2P,EAAM/K,UAAUkL,IAAM,SAAmBhM,GACrC,MAAOnG,MAAKiS,OAAO9L,IAIvB6L,EAAM/K,UAAUmL,IAAM,SAAmBjM,SAC9BnG,MAAKiS,OAAO9L,SAGjBkM,GAAG,SAAS3R,EAAQjB,EAAOD,GACjC,YAGAC,GAAOD,SACL8S,KAAQ5R,EAAQ,gBAChB6R,MAAO7R,EAAQ,kBACf8R,MAAO9R,EAAQ,kBACf+R,aAAc/R,EAAQ,yBACtBgS,OAAMhS,EAAQ,iBACdgK,OAAQhK,EAAQ,mBAChBiS,MAAOjS,EAAQ,kBACfkS,QAASlS,EAAQ,mBACjBmS,QAASnS,EAAQ,mBACjBoS,SAAUpS,EAAQ,wBAClBqS,SAAUrS,EAAQ,wBAClBsS,UAAWtS,EAAQ,yBACnBuS,UAAWvS,EAAQ,yBACnBwS,cAAexS,EAAQ,6BACvByS,cAAezS,EAAQ,6BACvB0S,WAAY1S,EAAQ,uBACpB2S,IAAK3S,EAAQ,gBACb4S,MAAO5S,EAAQ,kBACf6S,QAAS7S,EAAQ,oBACjB8S,WAAY9S,EAAQ,uBACpB+S,SAAU/S,EAAQ,qBAClBgT,YAAahT,EAAQ,wBACrBgR,SAAUhR,EAAQ,wBAGjBiT,kBAAkB,GAAGC,uBAAuB,GAAGC,wBAAwB,GAAGC,4BAA4B,GAAGC,iBAAiB,GAAGC,iBAAiB,GAAGC,wBAAwB,GAAGC,gBAAgB,GAAGC,kBAAkB,GAAGC,iBAAiB,GAAGC,sBAAsB,GAAGC,eAAe,GAAGC,iBAAiB,GAAGC,mBAAmB,GAAGC,sBAAsB,GAAGC,eAAe,GAAGC,oBAAoB,GAAGC,uBAAuB,GAAGC,oBAAoB,KAAKC,IAAI,SAASpU,EAAQjB,EAAOD,GACjd,YAEAC,GAAOD,QAAU,QAASuV,GAAMtU,EAAGuU,GACjC,GAAIvU,IAAMuU,EAAG,OAAO,CAEpB,IAEIrU,GAFAsU,EAAO/M,MAAMD,QAAQxH,GACrByU,EAAOhN,MAAMD,QAAQ+M,EAGzB,IAAIC,GAAQC,EAAM,CAChB,GAAIzU,EAAEO,QAAUgU,EAAEhU,OAAQ,OAAO,CACjC,KAAKL,EAAI,EAAOF,EAAEO,OAANL,EAAcA,IACxB,IAAKoU,EAAMtU,EAAEE,GAAIqU,EAAErU,IAAK,OAAO,CACjC,QAAO,EAGT,GAAIsU,GAAQC,EAAM,OAAO,CAEzB,IAAIzU,GAAKuU,GAAkB,gBAANvU,IAA+B,gBAANuU,GAAgB,CAC5D,GAAIlM,GAAO9B,OAAO8B,KAAKrI,EAEvB,IAAIqI,EAAK9H,SAAWgG,OAAO8B,KAAKkM,GAAGhU,OAAQ,OAAO,CAElD,KAAKL,EAAI,EAAOmI,EAAK9H,OAATL,EAAiBA,IAC3B,GAAmB+H,SAAfsM,EAAElM,EAAKnI,IAAmB,OAAO,CAEvC,KAAKA,EAAI,EAAOmI,EAAK9H,OAATL,EAAiBA,IAC3B,IAAIoU,EAAMtU,EAAEqI,EAAKnI,IAAKqU,EAAElM,EAAKnI,KAAM,OAAO,CAE5C,QAAO,EAGT,OAAO,QAGHwU,IAAI,SAASzU,EAAQjB,EAAOD,GAClC,YAgBA,SAAS4V,GAAQC,GACfA,EAAe,QAARA,EAAiB,OAAS,MACjC,IAAIC,GAAahL,EAAKiL,KAAKH,EAAQC,GACnC,KAAK,GAAIG,KAASJ,GAAQK,QACxBH,EAAWE,IACT9D,SAAU4D,EAAWE,GACrBC,QAASL,EAAQK,QAAQD,GAG7B,OAAOF,GAuDT,QAASI,GAAKC,GAEZ,GAAIC,GAAUD,EAAInI,MAAMqI,EACxB,KAAKD,EAAS,OAAO,CAErB,IAAIE,IAASF,EAAQ,GACjBG,GAAOH,EAAQ,EACnB,OAAOE,IAAS,GAAc,IAATA,GAAeC,GAAO,GAAYC,EAAKF,IAAZC,EAIlD,QAASE,GAAKN,EAAKO,GACjB,GAAIN,GAAUD,EAAInI,MAAM2I,EACxB,KAAKP,EAAS,OAAO,CAErB,IAAIQ,GAAOR,EAAQ,GACfS,EAAST,EAAQ,GACjBU,EAASV,EAAQ,GACjBW,EAAWX,EAAQ,EACvB,OAAe,KAARQ,GAAwB,IAAVC,GAA0B,IAAVC,KAAkBJ,GAAQK,GAKjE,QAASC,GAAUb,GAEjB,GAAIc,GAAWd,EAAI7T,MAAM4U,EACzB,OAAOhB,GAAKe,EAAS,KAAOR,EAAKQ,EAAS,IAAI,GAIhD,QAAS9M,GAASgM,GAEhB,MAAqB,MAAdA,EAAI3U,QAAiB2V,EAASlR,KAAKkQ,GAK5C,QAASiB,GAAIjB,GAEX,MAAOkB,GAAiBpR,KAAKkQ,IAAQmB,EAAIrR,KAAKkQ,GAIhD,QAASoB,GAAMpB,GACb,IAEE,MADA,IAAIqB,QAAOrB,IACJ,EACP,MAAMzV,GACN,OAAO,GAKX,QAAS+W,GAAYC,EAAIC,GACvB,MAAMD,IAAMC,EACRD,EAAKC,EAAW,EACXA,EAALD,EAAgB,GAChBA,IAAOC,EAAW,EAAtB,OAHA,OAOF,QAASC,GAAYC,EAAIC,GACvB,MAAMD,IAAMC,IACZD,EAAKA,EAAG7J,MAAM2I,GACdmB,EAAKA,EAAG9J,MAAM2I,GACRkB,GAAMC,IACZD,EAAKA,EAAG,GAAKA,EAAG,GAAKA,EAAG,IAAMA,EAAG,IAAI,IACrCC,EAAKA,EAAG,GAAKA,EAAG,GAAKA,EAAG,IAAMA,EAAG,IAAI,IACjCD,EAAKC,EAAW,EACXA,EAALD,EAAgB,GAChBA,IAAOC,EAAW,EAAtB,QARA,OAYF,QAASC,GAAgBC,EAAKC,GAC5B,GAAMD,GAAOC,EAAb,CACAD,EAAMA,EAAI1V,MAAM4U,GAChBe,EAAMA,EAAI3V,MAAM4U,EAChB,IAAIpO,GAAM2O,EAAYO,EAAI,GAAIC,EAAI,GAClC,IAAY/O,SAARJ,EACJ,MAAOA,IAAO8O,EAAYI,EAAI,GAAIC,EAAI,KA/JxC,GAAInN,GAAO5J,EAAQ,UAEfmV,EAAO,2BACPG,GAAQ,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAC3CG,EAAO,oDACPQ,EAAW,uFACXG,EAAM,moCACNY,EAAO,iEACPC,EAAe,0GACfC,EAAwB,2DAG5BnY,GAAOD,QAAU4V,EAejBA,EAAQyC,MAENnC,KAAM,6BAENO,KAAM,2DACN6B,YAAa,uFAEblB,IAAK,8CAILmB,MAAO,oHACPpO,SAAUgN,EAEVqB,KAAM,4EAENC,KAAM,qpCACNlB,MAAOA,EAEPmB,KAAMR,EAGNS,eAAgBR,EAEhBS,wBAAyBR,GAI3BxC,EAAQc,MACNR,KAAMA,EACNO,KAAMA,EACN6B,YAAatB,EACbI,IAAKA,EACLmB,MAAO,8IACPpO,SAAUA,EACVqO,KAAM,4EACNC,KAAM,qpCACNlB,MAAOA,EACPmB,KAAMR,EACNS,eAAgBR,EAChBS,wBAAyBR,GAI3BxC,EAAQK,SACNC,KAAMuB,EACNhB,KAAMmB,EACNU,YAAaP,EA2Bf,IAAIb,GAAsB,QActBG,EAAmB,UA+CpB1G,SAAS,KAAKkI,IAAI,SAAS3X,QAAQjB,OAAOD,SAC7C,YAcA,SAASoS,SAAQrB,OAAQrP,KAAMoX,UAAWC,QAoBxC,QAASC,cAAaC,QAASC,MAAOJ,UAAWC,QAC/C,GAAII,SAAUD,OAAUA,OAASA,MAAMnI,QAAUkI,OACjD,IAAIC,MAAMnI,QAAUrP,KAAKqP,OACvB,MAAOqB,SAAQ7Q,KAAKhB,KAAM0Y,QAASC,MAAOJ,UAAWC,OAEvD,IAAIK,cAAeC,mBACjBC,OAAO,EACPvI,OAAQkI,QACRE,OAAQA,OACRJ,OAAQA,OACRrX,KAAMwX,MACNK,WAAY,GACZC,cAAe,IACfC,UAAW,KACXC,MAAOA,MACPxH,SAAUmH,kBACVvO,KAAMA,KACNQ,QAASA,QACTqO,WAAYA,WACZC,WAAYA,WACZC,WAAYA,WACZC,cAAeA,cACf/H,KAAMxR,KAAKwR,KACX6D,QAASA,QACTrV,KAAMA,MAOR,IAJA6Y,aAAeW,KAAKC,OAAQC,YAAcF,KAAKG,SAAUC,aACxCJ,KAAKK,SAAUC,aAAeN,KAAKO,YAAaC,gBAChDnB,aAEb7Y,KAAKwR,KAAKyI,SAAU,CACtB,GAAIzI,MAAOxR,KAAKwR,KAAKyI,YAAa,GAASC,YAAa,GAAMla,KAAKwR,KAAKyI,QAEpEA,UAAUpB,aAAeoB,SAASpB,aAAcrH,MAC/C2I,QAAQ/Y,MAAM,oDAGrB,GAAIuQ,SACJ,KACEyI,KAAKvB,cACLY,OAAO,GAAK9H,SACZ,MAAMxR,GAEN,KADAga,SAAQE,IAAI,yCAA0CxB,cAChD1Y,EASR,MANAwR,UAASnB,OAASkI,QAClB/G,SAASpQ,OAAS,KAClBoQ,SAAS2I,KAAOA,KAChB3I,SAAS8H,OAASA,OAClB9H,SAASxQ,KAAOyX,OAASjH,SAAWgH,MAE7BhH,SAGT,QAASyH,YAAWZ,EAAQvH,EAAK2H,GAC/B3H,EAAMlG,QAAQX,IAAIoO,EAAQvH,EAC1B,IACIsJ,GAASC,EADTC,EAAWH,KAAKrJ,EAEpB,IAAiBtI,SAAb8R,EAGF,MAFAF,GAAUd,OAAOgB,GACjBD,EAAU,UAAYC,EAAW,IAC1BC,YAAYH,EAASC,EAE9B,KAAK5B,EAAQ,CACX,GAAI+B,GAAYxZ,KAAKmZ,KAAKrJ,EAC1B,IAAkBtI,SAAdgS,EAGF,MAFAJ,GAAUpZ,KAAKsY,OAAOkB,GACtBH,EAAUI,YAAY3J,EAAKsJ,GACpBG,YAAYH,EAASC,GAIhCA,EAAUI,YAAY3J,EACtB,IAAIrJ,GAAImD,QAAQ/J,KAAKhB,KAAMyY,aAActX,KAAM8P,EAC/C,KAAKrJ,EAAG,CACN,GAAIiT,GAActC,WAAaA,UAAUtH,EACrC4J,KACFjT,EAAImD,QAAQ+P,UAAUD,EAAa7a,KAAKwR,KAAKuJ,YACvCF,EACAhJ,QAAQ7Q,KAAKhB,KAAM6a,EAAa1Z,KAAMoX,UAAWC,IAI3D,MAAI5Q,IACFoT,gBAAgB/J,EAAKrJ,GACd8S,YAAY9S,EAAG4S,IAFxB,OAMF,QAASI,aAAY3J,EAAKrJ,GACxB,GAAIqT,GAAQxB,OAAOxY,MAGnB,OAFAwY,QAAOwB,GAASrT,EAChB0S,KAAKrJ,GAAOgK,EACL,SAAWA,EAGpB,QAASD,iBAAgB/J,EAAKrJ,GAC5B,GAAIqT,GAAQX,KAAKrJ,EACjBwI,QAAOwB,GAASrT,EAGlB,QAAS8S,aAAYlK,EAAQ1P,GAC3B,MAAwB,gBAAV0P,IACFA,OAAQA,EAAQ1P,KAAMA,GACxBA,EAGZ,QAASuY,YAAW6B,GAClB,GAAI/W,GAAQgX,aAAaD,EAKzB,OAJcvS,UAAVxE,IACFA,EAAQgX,aAAaD,GAAYvB,SAAS1Y,OAC1C0Y,SAASxV,GAAS+W,GAEb,UAAY/W,EAGrB,QAASmV,YAAWhX,GAClB,aAAeA,IACb,IAAK,UACL,IAAK,SACH,MAAO,GAAKA,CACd,KAAK,SACH,MAAOiI,MAAK6Q,eAAe9Y,EAC7B,KAAK,SACH,GAAc,OAAVA,EAAgB,MAAO,MAC3B,IAAI+Y,GAAWC,gBAAgBhZ,GAC3B6B,EAAQoX,aAAaF,EAKzB,OAJc1S,UAAVxE,IACFA,EAAQoX,aAAaF,GAAYxB,SAAS5Y,OAC1C4Y,SAAS1V,GAAS7B,GAEb,UAAY6B,GAIzB,QAASoV,eAAciC,EAAMhL,EAAQiL,EAAcC,GACjD,GAII/J,GAJAE,EAAU2J,EAAKG,WAAW9J,QAC1B+J,EAASJ,EAAKG,WAAWC,OACzBC,EAAQL,EAAKG,WAAWE,KAGxBhK,GACFF,EAAWE,EAAQ7Q,KAAKhB,KAAMwQ,EAAQiL,GAC/BI,GACPlK,EAAWkK,EAAM7a,KAAKhB,KAAMwQ,EAAQiL,GAChCzb,KAAKwR,KAAKsK,kBAAmB,GAAO9b,KAAK8b,eAAenK,GAAU,IAEtEA,EADSiK,EACEA,EAAO5a,KAAKhB,KAAM0b,EAAIF,EAAKO,QAASvL,EAAQiL,GAE5CD,EAAKG,WAAWhK,QAE7B,IAAIxN,GAAQ4V,YAAY9Y,MAGxB,OAFA8Y,aAAY5V,GAASwN,GAGnB7Q,KAAM,aAAeqD,EACrBwN,SAAUA,GAhLd,GAAI3R,MAAOC,KACPwZ,QAAW9Q,QACX2R,QACAX,YACAwB,gBACAtB,YACA0B,gBACAxB,eACAiC,kBAEJ7a,MAAOA,OAAUqP,OAAQA,OAAQiJ,OAAQA,OAAQa,KAAMA,KAEvD,IAAIjF,SAAUpV,KAAKgc,SACf9C,MAAQlZ,KAAKkZ,KAEjB,OAAOV,cAAajI,OAAQrP,KAAMoX,UAAWC,QAuK/C,QAASoB,aAAYhZ,EAAG+Y,GACtB,MAAO,cAAgB/Y,EAAI,iBAAmB2J,KAAK6Q,eAAezB,EAAS/Y,IAAM,KAInF,QAASkZ,aAAYlZ,GACnB,MAAO,cAAgBA,EAAI,eAAiBA,EAAI,KAIlD,QAAS8Y,YAAW9Y,EAAG6Y,GACrB,MAAOA,GAAO7Y,GAAK,aAAeA,EAAI,aAAeA,EAAI,KAAO,GAIlE,QAASoZ,gBAAepZ,GACtB,MAAO,iBAAmBA,EAAI,kBAAoBA,EAAI,KAIxD,QAAS4Y,MAAK0C,EAAKC,GACjB,IAAKD,EAAIjb,OAAQ,MAAO,EAExB,KAAK,GADDH,GAAO,GACFF,EAAE,EAAKsb,EAAIjb,OAANL,EAAcA,IAC1BE,GAAQqb,EAAUvb,EAAGsb,EACvB,OAAOpb,GA7NT,GAAIiK,SAAUpK,QAAQ,aAClB4J,KAAO5J,QAAQ,UACfqU,MAAQrU,QAAQ,WAChB2a,gBAAkB3a,QAAQ,yBAE1BsZ,SAAW,WAAc,IAAM,MAAOtZ,SAAQ,eAAoByb,YAAe,MAAMjc,QAEvF2Y,kBAAoBnY,QAAQ,oBAEhCjB,QAAOD,QAAUoS,OA4NjB,IAAIwK,YAAa9R,KAAK8R,aAEnBvH,oBAAoB,GAAGwH,UAAU,GAAGC,YAAY,GAAGnM,SAAS,GAAGoM,wBAAwB,KAAKC,IAAI,SAAS9b,EAAQjB,EAAOD,GAC3H,YAeA,SAASsL,GAAQ8G,EAAS1Q,EAAM8P,GAE9B,GAAIwI,GAASxZ,KAAK+Q,MAAMC,EACxB,IAAqB,gBAAVwI,GAAoB,CAC7B,IAAIxZ,KAAK+Q,MAAMyI,GACV,MAAO1O,GAAQ/J,KAAKf,KAAM4R,EAAS1Q,EAAMsY,EADtBA,GAASxZ,KAAK+Q,MAAMyI,GAK9C,GADAA,EAASA,GAAUxZ,KAAKiR,SAASD,GAC7BwI,YAAkBiD,GACpB,MAAO5B,GAAUrB,EAAOjJ,OAAQvQ,KAAKuR,KAAKuJ,YAChCtB,EAAOjJ,OACPiJ,EAAO9H,UAAY1R,KAAK0c,SAASlD,EAE7C,IACIjJ,GAAQ5I,EAAG4Q,EADXjQ,EAAMqU,EAAS5b,KAAKf,KAAMkB,EAAM8P,EAepC,OAbI1I,KACFiI,EAASjI,EAAIiI,OACbrP,EAAOoH,EAAIpH,KACXqX,EAASjQ,EAAIiQ,QAGXhI,YAAkBkM,GACpB9U,EAAI4I,EAAOmB,UAAYE,EAAQ7Q,KAAKf,KAAMuQ,EAAOA,OAAQrP,EAAMwH,OAAW6P,GACnEhI,IACP5I,EAAIkT,EAAUtK,EAAQvQ,KAAKuR,KAAKuJ,YAC1BvK,EACAqB,EAAQ7Q,KAAKf,KAAMuQ,EAAQrP,EAAMwH,OAAW6P,IAE7C5Q,EAIT,QAASgV,GAASzb,EAAM8P,GAEtB,GAAI3C,GAAIlE,EAAInB,MAAMgI,GAAK,GAAO,GAC1B4L,EAAUC,EAAaxO,GACvBkK,EAASuE,EAAY5b,EAAKqP,OAAOwM,GACrC,IAAIH,IAAYrE,EAAQ,CACtB,GAAIwE,GAAKC,EAAYJ,GACjBpD,EAASxZ,KAAK+Q,MAAMgM,EACxB,IAAqB,gBAAVvD,GACT,MAAOyD,GAAiBlc,KAAKf,KAAMkB,EAAMsY,EAAQnL,EAC5C,IAAImL,YAAkBiD,GACtBjD,EAAO9H,UAAU1R,KAAK0c,SAASlD,GACpCtY,EAAOsY,MAGP,IADAA,EAASxZ,KAAKiR,SAAS8L,GACnBvD,YAAkBiD,GAAc,CAElC,GADKjD,EAAO9H,UAAU1R,KAAK0c,SAASlD,GAChCuD,GAAMC,EAAYhM,GACpB,OAAST,OAAQiJ,EAAQtY,KAAMA,EAAMqX,OAAQA,EAC/CrX,GAAOsY,EAGX,IAAKtY,EAAKqP,OAAQ,MAClBgI,GAASuE,EAAY5b,EAAKqP,OAAOwM,IAEnC,MAAOG,GAAenc,KAAKf,KAAMqO,EAAGkK,EAAQrX,EAAKqP,OAAQrP,GAI3D,QAAS+b,GAAiB/b,EAAM8P,EAAKmM,GAEnC,GAAI7U,GAAMqU,EAAS5b,KAAKf,KAAMkB,EAAM8P,EACpC,IAAI1I,EAAK,CACP,GAAIiI,GAASjI,EAAIiI,OACbgI,EAASjQ,EAAIiQ,MAGjB,OAFArX,GAAOoH,EAAIpH,KACPqP,EAAOwM,KAAIxE,EAAS6E,EAAW7E,EAAQhI,EAAOwM,KAC3CG,EAAenc,KAAKf,KAAMmd,EAAW5E,EAAQhI,EAAQrP,IAMhE,QAASgc,GAAeC,EAAW5E,EAAQhI,EAAQrP,GAGjD,GADAic,EAAUvT,KAAOuT,EAAUvT,MAAQ,GACF,MAA7BuT,EAAUvT,KAAKlE,MAAM,EAAE,GAA3B,CAGA,IAAK,GAFD7D,GAAQsb,EAAUvT,KAAK9H,MAAM,KAExBnB,EAAI,EAAOkB,EAAMb,OAAVL,EAAkBA,IAAK,CACrC,GAAIoN,GAAOlM,EAAMlB,EACjB,IAAIoN,EAAM,CAGR,GAFAA,EAAOzD,EAAK+S,iBAAiBtP,GAC7BwC,EAASA,EAAOxC,IACXwC,EAAQ,KAEb,IADIA,EAAOwM,KAAOO,EAAqBvP,KAAOwK,EAAS6E,EAAW7E,EAAQhI,EAAOwM,KAC7ExM,EAAO+B,KAAM,CACf,GAAIA,GAAO8K,EAAW7E,EAAQhI,EAAO+B,MACjChK,EAAMqU,EAAS5b,KAAKf,KAAMkB,EAAMoR,EAChChK,KACFiI,EAASjI,EAAIiI,OACbrP,EAAOoH,EAAIpH,KACXqX,EAASjQ,EAAIiQ,UAKrB,MAAIhI,IAAUA,GAAUrP,EAAKqP,QAClBA,OAAQA,EAAQrP,KAAMA,EAAMqX,OAAQA,GAD/C,QAcF,QAASsC,GAAUtK,EAAQgN,GACzB,MAAc7U,UAAV6U,EAA4BC,EAAWjN,GAClCgN,EAAcE,EAAUlN,IAAWgN,EAAvC,OAIP,QAASC,GAAWjN,GAClB,GAAImN,EACJ,IAAIxV,MAAMD,QAAQsI,IAChB,IAAK,GAAI5P,GAAE,EAAK4P,EAAOvP,OAATL,EAAiBA,IAE7B,GADA+c,EAAOnN,EAAO5P,GACK,gBAAR+c,KAAqBF,EAAWE,GAAO,OAAO,MAG3D,KAAK,GAAIvX,KAAOoK,GAAQ,CACtB,GAAW,QAAPpK,EAAe,OAAO,CAGxB,IADAuX,EAAOnN,EAAOpK,GACK,gBAARuX,KAAqBF,EAAWE,GAAO,OAAO,EAI/D,OAAO,EAIT,QAASD,GAAUlN,GACjB,GAAemN,GAAXC,EAAQ,CACZ,IAAIzV,MAAMD,QAAQsI,IAChB,IAAK,GAAI5P,GAAE,EAAK4P,EAAOvP,OAATL,EAAiBA,IAG7B,GAFA+c,EAAOnN,EAAO5P,GACK,gBAAR+c,KAAkBC,GAASF,EAAUC,IAC5CC,GAASC,EAAAA,EAAU,MAAOA,GAAAA,MAGhC,KAAK,GAAIzX,KAAOoK,GAAQ,CACtB,GAAW,QAAPpK,EAAe,MAAOyX,GAAAA,CAC1B,IAAIC,EAAe1X,GAAMwX,QAIvB,IAFAD,EAAOnN,EAAOpK,GACK,gBAARuX,KAAkBC,GAASF,EAAUC,GAAQ,GACpDC,GAASC,EAAAA,EAAU,MAAOA,GAAAA,EAIpC,MAAOD,GAIT,QAASb,GAAYC,EAAIe,GACnBA,KAAc,IAAOf,EAAKC,EAAYD,GAC1C,IAAI1O,GAAIlE,EAAInB,MAAM+T,GAAI,GAAO,EAC7B,OAAOF,GAAaxO,GAItB,QAASwO,GAAaxO,GACpB,OAAQA,EAAE/E,UAAU,KAAO+E,EAAE/E,SAAS,KAAK,KAAO+E,EAAE5E,MAAM,KAAO4E,EAAErE,MAAM,IAAO,IAKlF,QAASgT,GAAYD,GACjB,MAAOA,GAAKA,EAAGhb,QAAQgc,EAAqB,IAAM,GAItD,QAASX,GAAW7E,EAAQwE,GAE1B,MADAA,GAAKC,EAAYD,GACV5S,EAAIW,QAAQyN,EAAQwE,GAI7B,QAASiB,GAAWzN,GAOlB,QAAS0N,GAAY1N,EAAQ2N,EAAU3F,GAErC,GAAIrQ,MAAMD,QAAQsI,GAChB,IAAK,GAAI5P,GAAE,EAAK4P,EAAOvP,OAATL,EAAiBA,IAC7Bsd,EAAYld,KAAKf,KAAMuQ,EAAO5P,GAAIud,EAAS,IAAIvd,EAAG4X,OACjD,IAAIhI,GAA2B,gBAAVA,GAAoB,CAC5C,GAAwB,gBAAbA,GAAOwM,GAAgB,CAChC,GAAIA,GAAKxE,EAASA,EACEpO,EAAIW,QAAQyN,EAAQhI,EAAOwM,IAC3BC,EAAYzM,EAAOwM,IAEnCvD,EAASxZ,KAAK+Q,MAAMgM,EAExB,IADqB,gBAAVvD,KAAoBA,EAASxZ,KAAK+Q,MAAMyI,IAC/CA,GAAUA,EAAOjJ,QACnB,IAAKwE,EAAMxE,EAAQiJ,EAAOjJ,QACxB,KAAM,IAAI3P,OAAM,OAASmc,EAAK,0CAC3B,IAAIA,GAAMC,EAAYkB,GAC3B,GAAa,KAATnB,EAAG,GAAW,CAChB,GAAIzE,EAAUyE,KAAQhI,EAAMxE,EAAQ+H,EAAUyE,IAC5C,KAAM,IAAInc,OAAM,OAASmc,EAAK,qCAChCzE,GAAUyE,GAAMxM,MAEhBvQ,MAAK+Q,MAAMgM,GAAMmB,EAGvB,IAAK,GAAI/X,KAAOoK,GACd0N,EAAYld,KAAKf,KAAMuQ,EAAOpK,GAAM+X,EAAS,IAAI5T,EAAK6T,eAAehY,GAAMoS,IA/BjF,GAAIwE,GAAKC,EAAYzM,EAAOwM,IACxBzE,IAEJ,OADA2F,GAAYld,KAAKf,KAAMuQ,EAAQuM,EAAYC,GAAI,GAAQA,GAChDzE,EA7MT,GAAInO,GAAMzJ,EAAQ,OACdqU,EAAQrU,EAAQ,WAChB4J,EAAO5J,EAAQ,UACf+b,EAAe/b,EAAQ,eAE3BjB,GAAOD,QAAUsL,EAEjBA,EAAQkS,YAAcA,EACtBlS,EAAQoT,SAAWpB,EACnBhS,EAAQX,IAAMiT,EACdtS,EAAQsT,IAAMJ,EACdlT,EAAQ+P,UAAYA,CA6EpB,IAAIyC,GAAuBhT,EAAK+T,QAAQ,aAAc,oBAAqB,OAAQ,eAAgB,gBA8B/FR,EAAiBvT,EAAK+T,QACxB,OAAQ,SAAU,UAClB,YAAa,YACb,gBAAiB,gBACjB,WAAY,WACZ,UAAW,UACX,cAAe,aACf,WAAY,SA+DVN,EAAsB,UAkDvB1B,UAAU,GAAGiC,eAAe,GAAGnO,SAAS,GAAGhG,IAAM,IAAIoU,IAAI,SAAS7d,EAAQjB,EAAOD,GACpF,YAEA,IAAIgf,GAAc9d,EAAQ,YACtB4J,EAAO5J,EAAQ,SAEnBjB,GAAOD,QAAU,WACf,GAAI0Z,KACA9X,KAAM,SACNqd,OAAS,UAAW,UAAW,gBAC/Brd,KAAM,SACNqd,OAAS,YAAa,YAAa,UAAW,YAC9Crd,KAAM,QACNqd,OAAS,WAAY,WAAY,cAAe,WAChDrd,KAAM,SACNqd,OAAS,gBAAiB,gBAAiB,WAAY,eAAgB,gBACvEA,OAAS,OAAQ,OAAQ,MAAO,QAAS,QAAS,UAqBtD,OAlBAvF,GAAMwF,KAAQ,OAAQ,uBAAwB,qBAC9CxF,EAAMyF,UAAa,kBAAmB,UAAW,KAAM,QAAS,cAAe,WAC/EzF,EAAM0F,OAAU,SAAU,UAAW,SAAU,QAAS,SAAU,UAAW,QAE7E1F,EAAM2F,QAAQ,SAAUC,GACtBA,EAAML,MAAQK,EAAML,MAAMld,IAAI,SAAUua,GAEtC,MADA5C,GAAMwF,IAAIhc,KAAKoZ,IAEbA,QAASA,EACTjb,KAAM2d,EAAY1C,QAKxB5C,EAAMyF,SAAWrU,EAAK+T,OAAOnF,EAAMwF,IAAIpT,OAAO4N,EAAMyF,WACpDzF,EAAMwF,IAAMpU,EAAK+T,OAAOnF,EAAMwF,KAC9BxF,EAAM0F,MAAQtU,EAAK+T,OAAOnF,EAAM0F,OAEzB1F,KAGN6F,WAAW,EAAE5O,SAAS,KAAK6O,IAAI,SAASte,EAAQjB,EAAOD,GAC1D,YAMA,SAASid,GAAa3V,GAClBwD,EAAKiL,KAAKzO,EAAK9G,MALnB,GAAIsK,GAAO5J,EAAQ,SAEnBjB,GAAOD,QAAUid,IAMdtM,SAAS,KAAK8O,IAAI,SAASve,EAAQjB,EAAOD,GAC7C,YA2BA,SAAS+V,GAAKhV,EAAG2e,GACfA,EAAKA,KACL,KAAK,GAAI/Y,KAAO5F,GAAG2e,EAAG/Y,GAAO5F,EAAE4F,EAC/B,OAAO+Y,GAIT,QAASC,GAAcC,EAAUC,EAAMC,GACrC,GAAIC,GAAQD,EAAS,QAAU,QAC3BE,EAAMF,EAAS,OAAS,OACxBG,EAAKH,EAAS,IAAM,GACpBI,EAAMJ,EAAS,GAAK,GACxB,QAAQF,GACN,IAAK,OAAQ,MAAOC,GAAOE,EAAQ,MACnC,KAAK,QAAS,MAAOE,GAAK,iBAAmBJ,EAAO,GACpD,KAAK,SAAU,MAAO,IAAMI,EAAKJ,EAAOG,EAClB,UAAYH,EAAOE,EAAQ,WAAaC,EACxCE,EAAM,iBAAmBL,EAAO,IACtD,KAAK,UAAW,MAAO,WAAaA,EAAOE,EAAQ,WAAaC,EACzCE,EAAM,IAAML,EAAO,QAC1C,SAAS,MAAO,UAAYA,EAAOE,EAAQ,IAAMH,EAAW,KAKhE,QAASO,GAAeC,EAAWP,GACjC,OAAQO,EAAU5e,QAChB,IAAK,GAAG,MAAOme,GAAcS,EAAU,GAAIP,GAAM,EACjD,SACE,GAAIxe,GAAO,GACP+d,EAAQP,EAAOuB,EACfhB,GAAMpd,OAASod,EAAMiB,SACvBhf,EAAO+d,EAAAA,QAAa,IAAK,KAAOS,EAAO,OACvCxe,GAAQ,UAAYwe,EAAO,uBACpBT,GAAAA,cACAA,GAAMpd,YACNod,GAAMiB,QAEXjB,EAAMkB,cAAelB,GAAMmB,OAC/B,KAAK,GAAI5f,KAAKye,GACZ/d,IAASA,EAAO,OAAS,IAAOse,EAAchf,EAAGkf,GAAM,EAEzD,OAAOxe,IAKb,QAASwd,GAAOpC,GAEd,IAAK,GADDrS,MACKjJ,EAAE,EAAKsb,EAAIjb,OAANL,EAAcA,IAAKiJ,EAAKqS,EAAItb,KAAM,CAChD,OAAOiJ,GAMT,QAASoW,GAAY7Z,GACnB,MAAqB,gBAAPA,GACJ,IAAMA,EAAM,IACZ8Z,EAAWxa,KAAKU,GACd,IAAMA,EACN,KAAOA,EAAIpE,QAAQme,EAAc,QAAU,KAIzD,QAASC,GAAaxK,GACpB,MAAOA,GAAI5T,QAAQme,EAAc,QAMnC,QAAS9D,GAAWzG,GAKlB,IAJA,GAGItT,GAHArB,EAAS,EACTwG,EAAMmO,EAAI3U,OACVof,EAAM,EAEG5Y,EAAN4Y,GACLpf,IACAqB,EAAQsT,EAAIlT,WAAW2d,KACnB/d,GAAS,OAAmB,OAATA,GAAyBmF,EAAN4Y,IAExC/d,EAAQsT,EAAIlT,WAAW2d,GACC,QAAX,MAAR/d,IAA2B+d,IAGpC,OAAOpf,GAIT,QAASqf,GAAc1K,EAAK2K,GAC1BA,GAAW,QACX,IAAI1K,GAAUD,EAAInI,MAAM,GAAIwJ,QAAOsJ,EAAS,KAC5C,OAAO1K,GAAUA,EAAQ5U,OAAS,EAIpC,QAASuf,GAAW5K,EAAK2K,EAASE,GAGhC,MAFAF,IAAW,WACXE,EAAOA,EAAKze,QAAQ,MAAO,QACpB4T,EAAI5T,QAAQ,GAAIiV,QAAOsJ,EAAS,KAAME,EAAO,MAOtD,QAASC,GAAY1c,GACnB,MAAOA,GAAIhC,QAAQ2e,EAAY,IACpB3e,QAAQ4e,EAAkB,IAC1B5e,QAAQ6e,EAAoB,cASzC,QAASC,GAAiB9c,GACxB,GAAI6R,GAAU7R,EAAIyJ,MAAMsT,EACxB,OAAIlL,IAA8B,IAAnBA,EAAQ5U,OACd+C,EAAIhC,QAAQgf,EAAe,IACvBhf,QAAQif,EAAcC,GAE1Bld,EAIX,QAASmd,GAAe3Q,EAAQkO,GAC9B,IAAK,GAAItY,KAAOoK,GAAQ,GAAIkO,EAAMtY,GAAM,OAAO,EAIjD,QAASgV,GAAexF,GACtB,MAAO,IAAOwK,EAAaxK,GAAO,IAIpC,QAASwL,GAAYC,EAAaZ,EAAMa,EAAcC,GACpD,GAAItX,GAAOqX,EACG,SAAab,GAAQc,EAAW,GAAK,8CACpCA,EAAW,SAAad,EAAO,SAAa,YAAiBA,EAAO,WACnF,OAAOe,GAAUH,EAAapX,GAIhC,QAASwX,GAAQJ,EAAara,EAAMsa,GAClC,GAAIrX,GACUmR,EADHkG,EACkB,IAAMI,EAAkB1a,GACxBiZ,EAAYjZ,GACzC,OAAOwa,GAAUH,EAAapX,GAKhC,QAAS0X,GAAQC,EAAOC,EAAKC,GAC3B,GAAIjM,GAAU+L,EAAMnU,MAAMoK,EAC1B,KAAKhC,EAAS,KAAM,IAAIhV,OAAM,kCAAoC+gB,EAClE,IAAI1R,IAAM2F,EAAQ,GACdkM,EAAclM,EAAQ,EAC1B,IAAmB,KAAfkM,EAAoB,CACtB,GAAI7R,GAAM2R,EAAK,KAAM,IAAIhhB,OAAM,gCAAkCqP,EAAK,gCAAkC2R,EACxG,OAAOC,GAAMD,EAAM3R,GAEnB,GAAIA,EAAK2R,EAAK,KAAM,IAAIhhB,OAAM,sBAAwBqP,EAAK,gCAAkC2R,EAC7F,IAAIvC,GAAO,QAAWuC,EAAM3R,GAAO,GACnC,KAAK6R,EAAa,MAAOzC,EAIzB,KAAK,GAFDmB,GAAOnB,EACP0C,EAAWD,EAAYhgB,MAAM,KACxBnB,EAAE,EAAKohB,EAAS/gB,OAAXL,EAAmBA,IAAK,CACpC,GAAIqhB,GAAUD,EAASphB,EACnBqhB,KACF3C,GAAQW,EAAYiC,EAAoBD,IACxCxB,GAAQ,OAASnB,GAGrB,MAAOmB,GAKX,QAASe,GAAW9gB,EAAGuU,GACrB,MAAS,MAALvU,EAAkBuU,GACdvU,EAAI,MAAQuU,GAAGjT,QAAQ,UAAW,IAI5C,QAASsb,GAAiB1H,GACxB,MAAOsM,GAAoBja,mBAAmB2N;CAIhD,QAASwI,GAAexI,GACtB,MAAO9M,oBAAmB4Y,EAAkB9L,IAI9C,QAAS8L,GAAkB9L,GACzB,MAAOA,GAAI5T,QAAQ,KAAM,MAAMA,QAAQ,MAAO,MAIhD,QAASkgB,GAAoBtM,GAC3B,MAAOA,GAAI5T,QAAQ,MAAO,KAAKA,QAAQ,MAAO,KArOhDtC,EAAOD,SACL+V,KAAMA,EACN4J,cAAeA,EACfQ,eAAgBA,EAChBtB,OAAQA,EACR2B,YAAaA,EACbG,aAAcA,EACd/D,WAAYA,EACZiE,cAAeA,EACfE,WAAYA,EACZE,YAAaA,EACbI,iBAAkBA,EAClBK,eAAgBA,EAChB7F,gBAAiB3a,EAAQ,yBACzBya,eAAgBA,EAChBgG,YAAaA,EACbK,QAASA,EACTE,QAASA,EACTrE,iBAAkBA,EAClBc,eAAgBA,EAChBsD,kBAAmBA,EA0DrB,IAAIxB,GAAa,wBACbC,EAAe,QAiDfQ,EAAa,gBACbC,EAAmB,uCACnBC,EAAqB,8CAQrBE,EAAgB,gBAChBC,EAAgB,kEAChBC,EAAe,uBACfC,EAAc,uCAsCdrJ,EAAwB,qCAqDzB2E,wBAAwB,KAAK2F,IAAI,SAASxhB,EAAQjB,EAAOD,GAC5D,YACAC,GAAOD,QAAU,SAA+Bic,EAAI0G,GAClD,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BO,EAAS,QAAUT,CAEvB,IADAte,GAAO,OAAS,EAAW,gBACvB0X,EAAGlK,KAAK7G,UAAW,EAErB,MADA3G,IAAO,IAAM,EAAW,WAG1B,IAAIgf,GAAgBtH,EAAGlL,OAAO7F,OAC5BsY,EAAgBvH,EAAGlK,KAAK0R,IAAMF,EAAcpB,MAC5CuB,EAAiB,EACnB,IAAIF,EAAe,CACjB,GAAIG,GAAqB1H,EAAGnR,KAAKoX,QAAQqB,EAAcpB,MAAOY,EAAU9G,EAAG2H,aACzEC,EAAU,SAAWhB,EACrBiB,EAAW,UAAYjB,CACzBte,IAAO,QAAU,EAAY,cAAgB,EAAuB,OAAS,EAAa,MAAQ,EAAY,OAAS,EAAY,gBAC9H,CACL,GAAIsf,GAAU5H,EAAGrG,QAAQ2N,EACzB,KAAMM,IAAWA,EAAQ5N,QAEvB,MADA1R,IAAO,KAAO,EAAW,WAG3B,IAAIuf,GAAW,UAAY7H,EAAGnR,KAAK0V,YAAY+C,GAAiB,WAElE,GAAIQ,GAAqB,iBAAZpB,EACXqB,EAAoB,mBAAqBD,EAAS,UAAY,WAC9DE,EAAchI,EAAGlL,OAAOiT,GACxBE,EAAcjI,EAAGlK,KAAK0R,IAAMQ,GAAeA,EAAY9B,MACvDgC,EAAMJ,EAAS,IAAM,IACrBK,EAAU,SAAWvB,EACnBwB,EAAUpI,EAAGlK,KAAK0R,IAAMR,EAAQd,MAChCmC,EAAeD,EAAUpI,EAAGnR,KAAKoX,QAAQe,EAAQd,MAAOY,EAAU9G,EAAG2H,aAAeX,CAKxF,IAJIoB,IACF9f,GAAO,cAAgB,EAAS,MAAQ,EAAiB,KACzD+f,EAAe,SAAWzB,GAExBqB,EAAa,CACf,GAAIK,GAAmBtI,EAAGnR,KAAKoX,QAAQ+B,EAAY9B,MAAOY,EAAU9G,EAAG2H,aACrEY,EAAa,YAAc3B,EAC3B4B,EAAU,KAAO5B,EACjB6B,EAAS,OAAUD,EAAU,MAC/BlgB,IAAO,kBAAoB,EAAS,MAAQ,EAAqB,KACjEggB,EAAmB,aAAe1B,EAClCte,GAAO,eAAiB,EAAqB,oBAAwB,EAAqB,qBAAuB,EAAW,YAC5H,IAAIqe,GAAgBoB,EAChBW,EAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,yBAA2B,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,kBACrKA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,gBAAmB,EAAsB,wBAE9C0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,OACH6e,IACFM,GAAkB,IAClBnf,GAAO,YAEL8f,IACF9f,GAAO,QAAU,EAAiB,mBAAqB,EAAW,4BAA8B,EAAiB,iBAAqB,EAAW,oBACjJmf,GAAkB,KAEhBF,IACFjf,GAAO,SAAW,EAAa,KAAO,EAAW,mBACjDmf,GAAkB,KAEpBnf,GAAO,QAAU,EAAY,MAAQ,EAAa,IAAM,EAAU,MAEhEA,GADE8f,EACK,GAAK,EAEL,GAAMpI,EAAGnR,KAAK6Q,eAAesH,GAEtC1e,GAAO,WAAa,EAAY,mBAAqB,EAAW,0BAA4B,EAAS,MAAQ,EAAqB,kBAAoB,EAAW,qBAAuB,EAAW,eAAiB,EAAS,MAAQ,EAAY,IAAM,EAAQ,QAAU,EAAY,IAAM,EAAQ,eAAiB,EAAW,WAAa,EAAS,eAAiB,EAAS,OAAU,EAAQ,QAAY,EAAQ,UAChZ,CACL,GAAIigB,GAAaP,KAAgB,EAC/BS,EAASP,CACNK,KAAYE,GAAU,IAC3B,IAAID,GAAU,IAAOC,EAAS,GAC1BL,KACF9f,GAAO,QAAU,EAAiB,mBAAqB,EAAW,4BAA8B,EAAiB,iBAAqB,EAAW,oBACjJmf,GAAkB,KAEhBF,IACFjf,GAAO,SAAW,EAAa,KAAO,EAAW,mBACjDmf,GAAkB,KAEpBnf,GAAO,QAAU,EAAY,MAAQ,EAAa,IAAM,EAAU,MAEhEA,GADE8f,EACK,GAAK,EAEL,GAAMpI,EAAGnR,KAAK6Q,eAAesH,GAEtC1e,GAAO,WAAa,EAAY,mBAAqB,EAAW,iBAAmB,EAAW,mBAAqB,EAAW,MAAQ,EAAY,IAAM,EACnJigB,IACHjgB,GAAO,KAETA,GAAO,MAETA,GAAO,GAAK,EAAmB,QAAU,EAAW,MACpD,IAAIqe,GAAgBD,EAChBgC,EAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,gBAAkB,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,yBAE9J1X,GADE8f,EACK,GAAK,EAEL,GAAMpI,EAAGnR,KAAK6Q,eAAesH,GAEtC1e,GAAO,OACH0X,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,0BAA6B,EAAW,KAE7CA,GADE8f,EACK,OAAU,EAAiB,OAE3B,GAAMpI,EAAGnR,KAAK6V,aAAasC,GAEpC1e,GAAO,QAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,eAELA,GADE8f,EACK,kBAAoB,EAEpB,GAAMpI,EAAGnR,KAAK6Q,eAAesH,GAEtC1e,GAAO,2CAA8C0X,EAAa,WAAI,YAAc,EAAU,KAEhG1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CAQZ,OAPAA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,UAIH0gB,IAAI,SAAS/jB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAAyBic,EAAI0G,GAC5C,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BsB,EAAUpI,EAAGlK,KAAK0R,IAAMR,EAAQd,MAChCmC,EAAeD,EAAUpI,EAAGnR,KAAKoX,QAAQe,EAAQd,MAAOY,EAAU9G,EAAG2H,aAAeX,CACpFoB,KACF9f,GAAO,cAAgB,EAAS,MAAQ,EAAiB,KACzD+f,EAAe,SAAWzB,EAE5B,IAAIkB,GAAqB,WAAZpB,EACXqB,EAAoBD,EAAS,mBAAqB,mBAClDE,EAAchI,EAAGlL,OAAOiT,GACxBE,EAAcjI,EAAGlK,KAAK0R,IAAMQ,GAAeA,EAAY9B,MACvDgC,EAAMJ,EAAS,IAAM,IACrBmB,EAASnB,EAAS,IAAM,GAC1B,IAAIG,EAAa,CACf,GAAIK,GAAmBtI,EAAGnR,KAAKoX,QAAQ+B,EAAY9B,MAAOY,EAAU9G,EAAG2H,aACrEY,EAAa,YAAc3B,EAC3B4B,EAAU,KAAO5B,EACjB6B,EAAS,OAAUD,EAAU,MAC/BlgB,IAAO,kBAAoB,EAAS,MAAQ,EAAqB,KACjEggB,EAAmB,aAAe1B,EAClCte,GAAO,iBAAmB,EAAS,gBAAkB,EAAqB,2BAA+B,EAAqB,qBAC9H,IAAIqe,GAAgBoB,EAChBW,EAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,mBAAqB,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,kBAC/JA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,gBAAmB,EAAsB,wBAE9C0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,eACH8f,IACF9f,GAAO,KAAO,EAAiB,4BAA8B,EAAiB,qBAEhFA,GAAO,eAAiB,EAAS,MAAQ,EAAqB,gBAAkB,EAAU,IAAM,EAAW,KAAO,EAAiB,MAAQ,EAAU,IAAM,EAAW,IAAM,EAAiB,cAAgB,EAAS,eAAiB,EAAS,OAAU,EAAQ,QAAY,EAAQ,UACjR,CACL,GAAIigB,GAAaP,KAAgB,EAC/BS,EAASP,CACNK,KAAYE,GAAU,IAC3B,IAAID,GAAU,IAAOC,EAAS,GAC9BngB,IAAO,SACH8f,IACF9f,GAAO,KAAO,EAAiB,4BAA8B,EAAiB,qBAEhFA,GAAO,IAAM,EAAU,IAAM,EACzBigB,IACFjgB,GAAO,KAETA,GAAO,IAAM,EAAiB,MAEhC,GAAIqe,GAAgBD,EAChBgC,EAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,UAAY,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,6BAA+B,EAAY,YAAc,EAAiB,gBAAkB,EAAe,MACjQA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,0BAA6B,EAAW,IAE7CA,GADE8f,EACK,OAAU,EAEV,GAAK,EAAY,KAGxBpI,EAAGlK,KAAK+S,UACVvgB,GAAO,eAELA,GADE8f,EACK,kBAAoB,EAEpB,GAAK,EAEd9f,GAAO,2CAA8C0X,EAAa,WAAI,YAAc,EAAU,KAEhG1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CAWZ,OAVAA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,MACH6e,IACF7e,GAAO,YAEFA,QAGH4gB,IAAI,SAASjkB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAA8Bic,EAAI0G,GACjD,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BsB,EAAUpI,EAAGlK,KAAK0R,IAAMR,EAAQd,MAChCmC,EAAeD,EAAUpI,EAAGnR,KAAKoX,QAAQe,EAAQd,MAAOY,EAAU9G,EAAG2H,aAAeX,CACpFoB,KACF9f,GAAO,cAAgB,EAAS,MAAQ,EAAiB,KACzD+f,EAAe,SAAWzB,EAE5B,IAAIsB,GAAkB,YAAZxB,EAAyB,IAAM,GACzCpe,IAAO,QACH8f,IACF9f,GAAO,KAAO,EAAiB,4BAA8B,EAAiB,qBAEhFA,GAAO,IAAM,EAAU,WAAa,EAAQ,IAAM,EAAiB,MACnE,IAAIqe,GAAgBD,EAChBgC,EAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,eAAiB,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,wBAA0B,EAAiB,MACtMA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,gCAELA,GADc,YAAZoe,EACK,OAEA,OAETpe,GAAO,SAELA,GADE8f,EACK,OAAU,EAAiB,OAE3B,GAAK,EAEd9f,GAAO,YAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,eAELA,GADE8f,EACK,kBAAoB,EAEpB,GAAK,EAEd9f,GAAO,2CAA8C0X,EAAa,WAAI,YAAc,EAAU,KAEhG1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CAWZ,OAVAA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,KACH6e,IACF7e,GAAO,YAEFA,QAGH6gB,IAAI,SAASlkB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAA+Bic,EAAI0G,GAClD,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BsB,EAAUpI,EAAGlK,KAAK0R,IAAMR,EAAQd,MAChCmC,EAAeD,EAAUpI,EAAGnR,KAAKoX,QAAQe,EAAQd,MAAOY,EAAU9G,EAAG2H,aAAeX,CACpFoB,KACF9f,GAAO,cAAgB,EAAS,MAAQ,EAAiB,KACzD+f,EAAe,SAAWzB,EAE5B,IAAIsB,GAAkB,aAAZxB,EAA0B,IAAM,GAC1Cpe,IAAO,QACH8f,IACF9f,GAAO,KAAO,EAAiB,4BAA8B,EAAiB,qBAG9EA,GADE0X,EAAGlK,KAAKsT,WAAY,EACf,IAAM,EAAU,WAEhB,eAAiB,EAAU,KAEpC9gB,GAAO,IAAM,EAAQ,IAAM,EAAiB,MAC5C,IAAIqe,GAAgBD,EAChBgC,EAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,gBAAkB,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,wBAA0B,EAAiB,MACvMA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,8BAELA,GADc,aAAZoe,EACK,SAEA,UAETpe,GAAO,SAELA,GADE8f,EACK,OAAU,EAAiB,OAE3B,GAAK,EAEd9f,GAAO,iBAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,eAELA,GADE8f,EACK,kBAAoB,EAEpB,GAAK,EAEd9f,GAAO,2CAA8C0X,EAAa,WAAI,YAAc,EAAU,KAEhG1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CAWZ,OAVAA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,KACH6e,IACF7e,GAAO,YAEFA,QAGH+gB,IAAI,SAASpkB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAAmCic,EAAI0G,GACtD,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BsB,EAAUpI,EAAGlK,KAAK0R,IAAMR,EAAQd,MAChCmC,EAAeD,EAAUpI,EAAGnR,KAAKoX,QAAQe,EAAQd,MAAOY,EAAU9G,EAAG2H,aAAeX,CACpFoB,KACF9f,GAAO,cAAgB,EAAS,MAAQ,EAAiB,KACzD+f,EAAe,SAAWzB,EAE5B,IAAIsB,GAAkB,iBAAZxB,EAA8B,IAAM,GAC9Cpe,IAAO,QACH8f,IACF9f,GAAO,KAAO,EAAiB,4BAA8B,EAAiB,qBAEhFA,GAAO,gBAAkB,EAAU,YAAc,EAAQ,IAAM,EAAiB,MAChF,IAAIqe,GAAgBD,EAChBgC,EAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,oBAAsB,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,wBAA0B,EAAiB,MAC3MA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,gCAELA,GADc,iBAAZoe,EACK,OAEA,OAETpe,GAAO,SAELA,GADE8f,EACK,OAAU,EAAiB,OAE3B,GAAK,EAEd9f,GAAO,iBAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,eAELA,GADE8f,EACK,kBAAoB,EAEpB,GAAK,EAEd9f,GAAO,2CAA8C0X,EAAa,WAAI,YAAc,EAAU,KAEhG1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CAWZ,OAVAA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,KACH6e,IACF7e,GAAO,YAEFA,QAGHghB,IAAI,SAASrkB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAAwBic,EAAI0G,GAC3C,GAAIpe,GAAM,IACN0e,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UACzBmC,EAAMvJ,EAAGnR,KAAKiL,KAAKkG,GACnByH,EAAiB,EACrB8B,GAAI1C,OACJ,IAAI2C,GAAOxC,CACX,IAAIwC,EAGF,IAFA,GAAIC,GAAMC,EAAK,GACbC,EAAKH,EAAKjkB,OAAS,EACTokB,EAALD,GACLD,EAAOD,EAAKE,GAAM,GACd1J,EAAGnR,KAAK4W,eAAegE,EAAMzJ,EAAGvC,MAAMwF,OACxCsG,EAAIzU,OAAS2U,EACbF,EAAIjM,WAAa2J,EAAc,IAAMyC,EAAK,IAC1CH,EAAIhM,cAAgB2J,EAAiB,IAAMwC,EAC3CphB,GAAO,IAAO0X,EAAG/J,SAASsT,GAAQ,KAC9BpC,IACF7e,GAAO,aAAgBihB,EAAS,MAAI,OACpC9B,GAAkB,KAS1B,OAJIN,KACF7e,GAAO,IAAOmf,EAAexd,MAAM,EAAG,KAExC3B,EAAM0X,EAAGnR,KAAKmW,YAAY1c,SAItBshB,IAAI,SAAS3kB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAAwBic,EAAI0G,GAC3C,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BO,EAAS,QAAUT,EACnBiD,EAAQ,SAAWjD,EACnB2C,EAAMvJ,EAAGnR,KAAKiL,KAAKkG,GACnByH,EAAiB,EACrB8B,GAAI1C,OACJ,IAAIiD,GAAiB9C,EAAQ+C,MAAM,SAASN,GAC1C,MAAOzJ,GAAGnR,KAAK4W,eAAegE,EAAMzJ,EAAGvC,MAAMwF,MAE/C,IAAI6G,EAAgB,CAClBxhB,GAAO,QAAU,EAAU,kBAAoB,EAAW,aAC1D,IAAI0hB,GAAgBhK,EAAG+I,aACvB/I,GAAG+I,cAAgBQ,EAAIR,eAAgB,CACvC,IAAIS,GAAOxC,CACX,IAAIwC,EAGF,IAFA,GAAIC,GAAMC,EAAK,GACbC,EAAKH,EAAKjkB,OAAS,EACTokB,EAALD,GACLD,EAAOD,EAAKE,GAAM,GAClBH,EAAIzU,OAAS2U,EACbF,EAAIjM,WAAa2J,EAAc,IAAMyC,EAAK,IAC1CH,EAAIhM,cAAgB2J,EAAiB,IAAMwC,EAC3CphB,GAAO,IAAO0X,EAAG/J,SAASsT,GAAQ,IAAM,EAAW,MAAQ,EAAW,YAAeA,EAAS,MAAI,UAAY,EAAW,OACzH9B,GAAkB,GAGtBzH,GAAG+I,cAAgBQ,EAAIR,cAAgBiB,EACvC1hB,GAAO,IAAM,EAAmB,SAAW,EAAW,oBAClD0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,SAAW,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,kBACrJA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,oDAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,OAETA,GAAO,kGAAoG,EAAU,iCAAmC,EAAU,sBAAwB,EAAU,4BAChM0X,EAAGlK,KAAKsR,YACV9e,GAAO,OAETA,EAAM0X,EAAGnR,KAAKmW,YAAY1c,OAEtB6e,KACF7e,GAAO,gBAGX,OAAOA,SAGH2hB,IAAI,SAAShlB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAA2Bic,EAAI0G,GAC9C,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BO,EAAS,QAAUT,EACnBwB,EAAUpI,EAAGlK,KAAK0R,IAAMR,EAAQd,MAChCmC,EAAeD,EAAUpI,EAAGnR,KAAKoX,QAAQe,EAAQd,MAAOY,EAAU9G,EAAG2H,aAAeX,CACpFoB,KACF9f,GAAO,cAAgB,EAAS,MAAQ,EAAiB,KACzD+f,EAAe,SAAWzB,GAEvBwB,IACH9f,GAAO,cAAgB,EAAS,qBAAuB,EAAgB,KAEzEA,GAAO,OAAS,EAAW,YAAc,EAAU,WAAa,EAAS,WAAa,EAAW,QACjG,IAAIogB,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,YAAc,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,kBACxJA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,8CAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CAQZ,OAPAA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,WAIH4hB,IAAI,SAASjlB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAA+Bic,EAAI0G,GAClD,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9B+C,EAAQ,SAAWjD,EACnB2C,EAAMvJ,EAAGnR,KAAKiL,KAAKkG,GACnByH,EAAiB,EACrB8B,GAAI1C,OACJ,IAAIsD,MACFC,IACF,KAAKC,IAAarD,GAAS,CACzB,GAAIyC,GAAOzC,EAAQqD,GACfC,EAAQ7d,MAAMD,QAAQid,GAAQW,EAAgBD,CAClDG,GAAMD,GAAaZ,EAErBnhB,GAAO,OAAS,EAAU,YAC1B,IAAIiiB,GAAoBvK,EAAGxC,SAC3BlV,IAAO,cAAgB,EAAS,GAChC,KAAK,GAAI+hB,KAAaD,GAAe,CACnCE,EAAQF,EAAcC,GACtB/hB,GAAO,QAAU,EAAW0X,EAAGnR,KAAK0V,YAAY8F,GAAc,sBAC9D,IAAIb,GAAOc,CACX,IAAId,EAGF,IAFA,GAAIgB,GAAYd,EAAK,GACnBC,EAAKH,EAAKjkB,OAAS,EACTokB,EAALD,GAAS,CACdc,EAAahB,EAAKE,GAAM,GACpBA,IACFphB,GAAO,OAET,IAAImiB,GAAQzK,EAAGnR,KAAK0V,YAAYiG,EAChCliB,IAAO,MAAQ,EAAU,EAAU,6BAA+B,EAAS,MAAS0X,EAAGnR,KAAK6Q,eAAeM,EAAGlK,KAAK8P,aAAe4E,EAAaC,GAAU,OAG7JniB,GAAO,QACP,IAAIoiB,GAAgB,UAAY9D,EAC9B+D,EAAmB,OAAUD,EAAgB,MAC3C1K,GAAGlK,KAAK8U,yBACV5K,EAAGxC,UAAYwC,EAAGlK,KAAK8P,aAAe5F,EAAGnR,KAAK6W,YAAY6E,EAAmBG,GAAe,GAAQH,EAAoB,MAAQG,EAElI,IAAIhC,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,gBAAkB,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,6BAAgCA,EAAGnR,KAAK6V,aAAa2F,GAAc,wBAA4B,EAAqB,iBAAqBC,EAAY,OAAI,YAAgBtK,EAAGnR,KAAK6V,aAA6B,GAAhB4F,EAAM/kB,OAAc+kB,EAAM,GAAKA,EAAM5jB,KAAK,OAAU,OAC9YsZ,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,4BAELA,GADkB,GAAhBgiB,EAAM/kB,OACD,YAAeya,EAAGnR,KAAK6V,aAAa4F,EAAM,IAE1C,cAAiBtK,EAAGnR,KAAK6V,aAAa4F,EAAM5jB,KAAK,OAE1D4B,GAAO,kBAAqB0X,EAAGnR,KAAK6V,aAAa2F,GAAc,iBAE7DrK,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,QACH6e,IACFM,GAAkB,IAClBnf,GAAO,YAGX0X,EAAGxC,UAAY+M,CACf,KAAK,GAAIF,KAAaF,GAAa,CACjC,GAAIV,GAAOU,EAAYE,EACnBrK,GAAGnR,KAAK4W,eAAegE,EAAMzJ,EAAGvC,MAAMwF,OACxC3a,GAAO,SAAYihB,EAAS,MAAI,gBAAkB,EAAU,KAAQ,EAAc,uBAClFA,EAAIzU,OAAS2U,EACbF,EAAIjM,WAAa2J,EAAcjH,EAAGnR,KAAK0V,YAAY8F,GACnDd,EAAIhM,cAAgB2J,EAAiB,IAAMlH,EAAGnR,KAAK6T,eAAe2H,GAClE/hB,GAAO,IAAO0X,EAAG/J,SAASsT,GAAQ,OAC9BpC,IACF7e,GAAO,aAAgBihB,EAAS,MAAI,OACpC9B,GAAkB,MAQxB,MAJIN,KACF7e,GAAO,MAAQ,EAAmB,QAAU,EAAU,iBAExDA,EAAM0X,EAAGnR,KAAKmW,YAAY1c,SAItBuiB,IAAI,SAAS5lB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAAuBic,EAAI0G,GAC1C,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BO,EAAS,QAAUT,EACnBwB,EAAUpI,EAAGlK,KAAK0R,IAAMR,EAAQd,MAChCmC,EAAeD,EAAUpI,EAAGnR,KAAKoX,QAAQe,EAAQd,MAAOY,EAAU9G,EAAG2H,aAAeX,CACpFoB,KACF9f,GAAO,cAAgB,EAAS,MAAQ,EAAiB,KACzD+f,EAAe,SAAWzB,EAE5B,IAAI8C,GAAK,IAAM9C,CACVwB,KACH9f,GAAO,cAAgB,EAAS,qBAAuB,EAAgB,KAEzEA,GAAO,OAAS,EAAW,IACvB8f,IACF9f,GAAO,cAAgB,EAAS,mBAAqB,EAAW,0CAA4C,EAAS,MAAQ,EAAW,oBAE1IA,GAAO,GAAK,EAAW,qBAAuB,EAAO,OAAS,EAAO,UAAY,EAAS,YAAc,EAAO,iBAAmB,EAAU,WAAa,EAAS,IAAM,EAAO,SAAW,EAAW,oBACjM8f,IACF9f,GAAO,SAETA,GAAO,SAAW,EAAW,QAC7B,IAAIogB,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,QAAU,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,kBACpJA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,mDAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CAWZ,OAVAA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,KACH6e,IACF7e,GAAO,YAEFA,QAGHwiB,IAAI,SAAS7lB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAAyBic,EAAI0G,GAC5C,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,GAClC,IAAI9G,EAAGlK,KAAK7G,UAAW,EAIrB,MAHIkY,KACF7e,GAAO,iBAEFA,CAET,IAAI8f,GAAUpI,EAAGlK,KAAK0R,IAAMR,EAAQd,MAChCmC,EAAeD,EAAUpI,EAAGnR,KAAKoX,QAAQe,EAAQd,MAAOY,EAAU9G,EAAG2H,aAAeX,CAKxF,IAJIoB,IACF9f,GAAO,cAAgB,EAAS,MAAQ,EAAiB,KACzD+f,EAAe,SAAWzB,GAExBwB,EAAS,CACX,GAAIR,GAAU,SAAWhB,CACzBte,IAAO,QAAU,EAAY,cAAgB,EAAiB,kBAAoB,EAAS,aAAe,EAAY,qBAAyB,EAAY,0BAA4B,EAAY,0BAA4B,EAAS,KAAO,EAAY,MAAQ,EAAY,sBAC3Q8f,IACF9f,GAAO,KAAO,EAAiB,4BAA8B,EAAiB,qBAEhFA,GAAO,KAAO,EAAY,gBAAkB,EAAY,oBAAwB,EAAY,IAAM,EAAU,OAAS,EAAY,SAAW,EAAU,aACjJ,CACL,GAAIsf,GAAU5H,EAAGrG,QAAQqN,EACzB,KAAKY,EAIH,MAHIT,KACF7e,GAAO,iBAEFA,CAET,IAAIyiB,GAA8B,gBAAXnD,MAAyBA,YAAmBrM,UAAWqM,EAAQ3R,QAClF8U,KAAWnD,EAAUA,EAAQ3R,UACjC3N,GAAO,SACP,IAAI0iB,GAAa,UAAYhL,EAAGnR,KAAK0V,YAAYyC,EAC7C+D,KAAWC,GAAc,aAE3B1iB,GADoB,kBAAXsf,GACF,IAAM,EAAe,IAAM,EAAU,KAErC,IAAM,EAAe,SAAW,EAAU,KAEnDtf,GAAO,MAET,GAAIogB,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,UAAY,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,0BAExJ1X,GADE8f,EACK,GAAK,EAEL,GAAMpI,EAAGnR,KAAK6Q,eAAesH,GAEtC1e,GAAO,OACH0X,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,sCAELA,GADE8f,EACK,OAAU,EAAiB,OAE3B,GAAMpI,EAAGnR,KAAK6V,aAAasC,GAEpC1e,GAAO,QAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,eAELA,GADE8f,EACK,kBAAoB,EAEpB,GAAMpI,EAAGnR,KAAK6Q,eAAesH,GAEtC1e,GAAO,2CAA8C0X,EAAa,WAAI,YAAc,EAAU,KAEhG1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CAWZ,OAVAA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,MACH6e,IACF7e,GAAO,YAEFA,QAGH2iB,IAAI,SAAShmB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAAwBic,EAAI0G,GAC3C,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BO,EAAS,QAAUT,EACnBiD,EAAQ,SAAWjD,EACnB2C,EAAMvJ,EAAGnR,KAAKiL,KAAKkG,GACnByH,EAAiB,EACrB8B,GAAI1C,OACJ,IAAIqE,GAAW3B,EAAIxC,UAAY/G,EAAG+G,UAAY,EAC5CoE,EAAY,OAASD,CAEvB,IADA5iB,GAAO,OAAS,EAAU,iBAAmB,EAAW,IACpDmE,MAAMD,QAAQwa,GAAU,CAC1B,GAAIoE,GAAmBpL,EAAGlL,OAAOuW,eACjC,IAAID,KAAqB,EAAO,CAC9B9iB,GAAO,IAAM,EAAW,MAAQ,EAAU,cAAiB0e,EAAc,OAAI,IAC7E,IAAIsE,GAAqBpE,CACzBA,GAAiBlH,EAAGzC,cAAgB,mBACpCjV,GAAO,UAAY,EAAW,QAC9B,IAAIogB,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,mBAAqB,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,wBAA2BgH,EAAc,OAAI,MAC5MhH,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,0CAA8C0e,EAAc,OAAI,YAErEhH,EAAGlK,KAAK+S,UACVvgB,GAAO,mDAAsD0X,EAAa,WAAI,YAAc,EAAU,KAExG1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,MACP4e,EAAiBoE,EACbnE,IACFM,GAAkB,IAClBnf,GAAO,YAGX,GAAIkhB,GAAOxC,CACX,IAAIwC,EAGF,IAFA,GAAIC,GAAMC,EAAK,GACbC,EAAKH,EAAKjkB,OAAS,EACTokB,EAALD,GAEL,GADAD,EAAOD,EAAKE,GAAM,GACd1J,EAAGnR,KAAK4W,eAAegE,EAAMzJ,EAAGvC,MAAMwF,KAAM,CAC9C3a,GAAO,SAAYihB,EAAS,MAAI,gBAAkB,EAAU,aAAe,EAAO,MAClF,IAAIgC,GAAYrF,EAAQ,IAAMwD,EAAK,GACnCH,GAAIzU,OAAS2U,EACbF,EAAIjM,WAAa2J,EAAc,IAAMyC,EAAK,IAC1CH,EAAIhM,cAAgB2J,EAAiB,IAAMwC,EAC3CH,EAAI/L,UAAYwC,EAAGnR,KAAK6W,YAAY1F,EAAGxC,UAAWkM,EAAI1J,EAAGlK,KAAK8P,cAAc,GACxE5F,EAAGlK,KAAK0R,KAAI+B,EAAI5B,YAAYuD,GAAYxB,EAC5C,IAAI8B,GAAQxL,EAAG/J,SAASsT,EAEtBjhB,IADE0X,EAAGnR,KAAK+V,cAAc4G,EAAOL,GAAa,EACrC,IAAOnL,EAAGnR,KAAKiW,WAAW0G,EAAOL,EAAWI,GAAc,IAE1D,QAAU,EAAc,MAAQ,EAAc,KAAO,EAAU,IAExEjjB,GAAO,OACH6e,IACF7e,GAAO,aAAgBihB,EAAS,MAAI,OACpC9B,GAAkB,KAK1B,GAA+B,gBAApB2D,IAAgCpL,EAAGnR,KAAK4W,eAAe2F,EAAkBpL,EAAGvC,MAAMwF,KAAM,CACjGsG,EAAIzU,OAASsW,EACb7B,EAAIjM,WAAa0C,EAAG1C,WAAa,mBACjCiM,EAAIhM,cAAgByC,EAAGzC,cAAgB,mBACvCjV,GAAO,SAAYihB,EAAS,MAAI,gBAAkB,EAAU,aAAgBvC,EAAc,OAAI,kBAAoB,EAAS,MAASA,EAAc,OAAI,MAAQ,EAAS,MAAQ,EAAU,aAAe,EAAS,SACjNuC,EAAI/L,UAAYwC,EAAGnR,KAAK6W,YAAY1F,EAAGxC,UAAW,IAAMoJ,EAAM5G,EAAGlK,KAAK8P,cAAc,EACpF,IAAI2F,GAAYrF,EAAQ,KAAOU,EAAO,GAClC5G,GAAGlK,KAAK0R,KAAI+B,EAAI5B,YAAYuD,GAAY,IAAMtE,EAClD,IAAI4E,GAAQxL,EAAG/J,SAASsT,EAEtBjhB,IADE0X,EAAGnR,KAAK+V,cAAc4G,EAAOL,GAAa,EACrC,IAAOnL,EAAGnR,KAAKiW,WAAW0G,EAAOL,EAAWI,GAAc,IAE1D,QAAU,EAAc,MAAQ,EAAc,KAAO,EAAU,IAEpEpE,IACF7e,GAAO,cAAiBihB,EAAS,MAAI,aAEvCjhB,GAAO,SACH6e,IACF7e,GAAO,aAAgBihB,EAAS,MAAI,OACpC9B,GAAkB,UAGjB,IAAIzH,EAAGnR,KAAK4W,eAAeuB,EAAShH,EAAGvC,MAAMwF,KAAM,CACxDsG,EAAIzU,OAASkS,EACbuC,EAAIjM,WAAa2J,EACjBsC,EAAIhM,cAAgB2J,EACpB5e,GAAO,eAAiB,EAAS,UAAsB,EAAS,MAAQ,EAAU,aAAe,EAAS,SAC1GihB,EAAI/L,UAAYwC,EAAGnR,KAAK6W,YAAY1F,EAAGxC,UAAW,IAAMoJ,EAAM5G,EAAGlK,KAAK8P,cAAc,EACpF,IAAI2F,GAAYrF,EAAQ,KAAOU,EAAO,GAClC5G,GAAGlK,KAAK0R,KAAI+B,EAAI5B,YAAYuD,GAAY,IAAMtE,EAClD,IAAI4E,GAAQxL,EAAG/J,SAASsT,EAEtBjhB,IADE0X,EAAGnR,KAAK+V,cAAc4G,EAAOL,GAAa,EACrC,IAAOnL,EAAGnR,KAAKiW,WAAW0G,EAAOL,EAAWI,GAAc,IAE1D,QAAU,EAAc,MAAQ,EAAc,KAAO,EAAU,IAEpEpE,IACF7e,GAAO,cAAiBihB,EAAS,MAAI,aAEvCjhB,GAAO,OACH6e,IACF7e,GAAO,aAAgBihB,EAAS,MAAI,OACpC9B,GAAkB,KAOtB,MAJIN,KACF7e,GAAO,IAAM,EAAmB,QAAU,EAAU,iBAEtDA,EAAM0X,EAAGnR,KAAKmW,YAAY1c,SAItBmjB,IAAI,SAASxmB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAA6Bic,EAAI0G,GAChD,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BsB,EAAUpI,EAAGlK,KAAK0R,IAAMR,EAAQd,MAChCmC,EAAeD,EAAUpI,EAAGnR,KAAKoX,QAAQe,EAAQd,MAAOY,EAAU9G,EAAG2H,aAAeX,CACpFoB,KACF9f,GAAO,cAAgB,EAAS,MAAQ,EAAiB,KACzD+f,EAAe,SAAWzB,GAE5Bte,GAAO,eAAiB,EAAS,QAC7B8f,IACF9f,GAAO,IAAM,EAAiB,8BAAgC,EAAiB,oBAEjFA,GAAO,aAAe,EAAS,MAAQ,EAAU,MAAQ,EAAiB,KAExEA,GADE0X,EAAGlK,KAAK4V,oBACH,gCAAkC,EAAS,eAAiB,EAAS,UAAa1L,EAAGlK,KAAwB,oBAAI,IAEjH,YAAc,EAAS,yBAA2B,EAAS,KAEpExN,GAAO,MACH8f,IACF9f,GAAO,SAETA,GAAO,SACP,IAAIogB,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,cAAgB,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,6BAA+B,EAAiB,MAC1MA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,sCAELA,GADE8f,EACK,OAAU,EAEV,GAAK,EAAY,KAGxBpI,EAAGlK,KAAK+S,UACVvgB,GAAO,eAELA,GADE8f,EACK,kBAAoB,EAEpB,GAAK,EAEd9f,GAAO,2CAA8C0X,EAAa,WAAI,YAAc,EAAU,KAEhG1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CAWZ,OAVAA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,KACH6e,IACF7e,GAAO,YAEFA,QAGHqjB,IAAI,SAAS1mB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAAsBic,EAAI0G,GACzC,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9B+C,EAAQ,SAAWjD,EACnB2C,EAAMvJ,EAAGnR,KAAKiL,KAAKkG,EAEvB,IADAuJ,EAAI1C,QACA7G,EAAGnR,KAAK4W,eAAeuB,EAAShH,EAAGvC,MAAMwF,KAAM,CACjDsG,EAAIzU,OAASkS,EACbuC,EAAIjM,WAAa2J,EACjBsC,EAAIhM,cAAgB2J,EACpB5e,GAAO,QAAU,EAAU,cAC3B,IAAI0hB,GAAgBhK,EAAG+I,aACvB/I,GAAG+I,cAAgBQ,EAAIR,eAAgB,EACvCQ,EAAIZ,cAAe,EACnBrgB,GAAO,IAAO0X,EAAG/J,SAASsT,GAAQ,IAClCA,EAAIZ,cAAe,EACnB3I,EAAG+I,cAAgBQ,EAAIR,cAAgBiB,EACvC1hB,GAAO,aAAgBihB,EAAS,MAAI,QACpC,IAAIb,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,OAAS,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,kBACnJA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,sCAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,uBAAyB,EAAU,iCAAmC,EAAU,sBAAwB,EAAU,4BACrH0X,EAAGlK,KAAKsR,YACV9e,GAAO,WAGTA,IAAO,iBACH0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,OAAS,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,kBACnJA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,sCAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,OAETA,GAAO,+EACH6e,IACF7e,GAAO,iBAGX,OAAOA,SAGHsjB,IAAI,SAAS3mB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAAwBic,EAAI0G,GAC3C,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BO,EAAS,QAAUT,EACnBiD,EAAQ,SAAWjD,EACnB2C,EAAMvJ,EAAGnR,KAAKiL,KAAKkG,GACnByH,EAAiB,EACrB8B,GAAI1C,QACJve,GAAO,OAAS,EAAU,0BAA4B,EAAS,gBAAkB,EAAW,YAC5F,IAAI0hB,GAAgBhK,EAAG+I,aACvB/I,GAAG+I,cAAgBQ,EAAIR,eAAgB,CACvC,IAAIS,GAAOxC,CACX,IAAIwC,EAGF,IAFA,GAAIC,GAAMC,EAAK,GACbC,EAAKH,EAAKjkB,OAAS,EACTokB,EAALD,GACLD,EAAOD,EAAKE,GAAM,GACd1J,EAAGnR,KAAK4W,eAAegE,EAAMzJ,EAAGvC,MAAMwF,MACxCsG,EAAIzU,OAAS2U,EACbF,EAAIjM,WAAa2J,EAAc,IAAMyC,EAAK,IAC1CH,EAAIhM,cAAgB2J,EAAiB,IAAMwC,EAC3CphB,GAAO,IAAO0X,EAAG/J,SAASsT,GAAQ,KAElCjhB,GAAO,aAAgBihB,EAAS,MAAI,YAElCG,IACFphB,GAAO,aAAgBihB,EAAS,MAAI,gBAAkB,EAAS,KAAO,EAAW,oBACjF9B,GAAkB,KAEpBnf,GAAO,aAAgBihB,EAAS,MAAI,KAAO,EAAW,eAAiB,EAAS,UAGpFvJ,GAAG+I,cAAgBQ,EAAIR,cAAgBiB,EACvC1hB,GAAO,GAAK,EAAmB,QAAU,EAAW,QACpD,IAAIogB,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,SAAW,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,kBACrJA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,2DAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CAWZ,OAVAA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,sBAAwB,EAAU,iCAAmC,EAAU,sBAAwB,EAAU,2BACpH0X,EAAGlK,KAAKsR,YACV9e,GAAO,OAEFA,QAGHujB,IAAI,SAAS5mB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAA0Bic,EAAI0G,GAC7C,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BsB,EAAUpI,EAAGlK,KAAK0R,IAAMR,EAAQd,MAChCmC,EAAeD,EAAUpI,EAAGnR,KAAKoX,QAAQe,EAAQd,MAAOY,EAAU9G,EAAG2H,aAAeX,CACpFoB,KACF9f,GAAO,cAAgB,EAAS,MAAQ,EAAiB,KACzD+f,EAAe,SAAWzB,EAE5B,IAAIkF,GAAU1D,EAAU,eAAiBC,EAAe,KAAOrI,EAAGrC,WAAWqJ,EAC7E1e,IAAO,QACH8f,IACF9f,GAAO,KAAO,EAAiB,4BAA8B,EAAiB,qBAEhFA,GAAO,KAAO,EAAY,SAAW,EAAU,UAC/C,IAAIogB,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,WAAa,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,2BAEzJ1X,GADE8f,EACK,GAAK,EAEL,GAAMpI,EAAGnR,KAAK6Q,eAAesH,GAEtC1e,GAAO,OACH0X,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,uCAELA,GADE8f,EACK,OAAU,EAAiB,OAE3B,GAAMpI,EAAGnR,KAAK6V,aAAasC,GAEpC1e,GAAO,QAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,eAELA,GADE8f,EACK,kBAAoB,EAEpB,GAAMpI,EAAGnR,KAAK6Q,eAAesH,GAEtC1e,GAAO,2CAA8C0X,EAAa,WAAI,YAAc,EAAU,KAEhG1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CAWZ,OAVAA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,KACH6e,IACF7e,GAAO,YAEFA,QAGHyjB,IAAI,SAAS9mB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAA6Bic,EAAI0G,GAChD,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BO,EAAS,QAAUT,EACnBiD,EAAQ,SAAWjD,EACnB2C,EAAMvJ,EAAGnR,KAAKiL,KAAKkG,GACnByH,EAAiB,EACrB8B,GAAI1C,OACJ,IAAIqE,GAAW3B,EAAIxC,UAAY/G,EAAG+G,UAAY,EAC5CoE,EAAY,OAASD,EACnBc,EAAczgB,OAAO8B,KAAK2Z,OAC5BiF,EAAejM,EAAGlL,OAAOoX,sBACzBC,EAAiB5gB,OAAO8B,KAAK4e,GAC7BG,EAAepM,EAAGlL,OAAOuX,qBACzBC,EAAkBN,EAAYzmB,QAAU4mB,EAAe5mB,OACvDgnB,EAAgBH,KAAiB,EACjCI,EAA6C,gBAAhBJ,IAA4B7gB,OAAO8B,KAAK+e,GAAc7mB,OACnFknB,EAAoBzM,EAAGlK,KAAK4W,iBAC5BC,EAAmBJ,GAAiBC,GAAuBC,EACzDG,EAAY5M,EAAGlL,OAAOkD,QAC1B,IAAI4U,KAAe5M,EAAGlK,KAAK0R,KAAMoF,EAAU1G,QAA6BlG,EAAGlK,KAAK+W,aAA3BD,EAAUrnB,OAA+B,GAAIunB,GAAgB9M,EAAGnR,KAAK+T,OAAOgK,EACjI,IAAI5M,EAAGlK,KAAK0R,GACV,GAAIuF,GAAgB/M,EAAGlL,OAAOkY,kBAC5BC,EAAkB1hB,OAAO8B,KAAK0f,EAGlC,IADAzkB,GAAO,OAAS,EAAU,sBAAyBihB,EAAS,MAAI,WAC5DoD,EAAkB,CAEpB,GADArkB,GAAO,gBAAkB,EAAS,OAAS,EAAU,OACjDgkB,EAAiB,CAEnB,GADAhkB,GAAO,oBAAsB,EAAS,cAClC0jB,EAAYzmB,OACd,GAAIymB,EAAYzmB,OAAS,EACvB+C,GAAO,sBAAwB,EAAgB,OAAS,EAAS,SAC5D,CACL,GAAIkhB,GAAOwC,CACX,IAAIxC,EAGF,IAFA,GAAI0D,GAAcC,EAAK,GACrBxD,EAAKH,EAAKjkB,OAAS,EACTokB,EAALwD,GACLD,EAAe1D,EAAK2D,GAAM,GAC1B7kB,GAAO,UAAY,EAAS,OAAU0X,EAAGnR,KAAK6Q,eAAewN,GAAiB,IAKtF,GAAIf,EAAe5mB,OAAQ,CACzB,GAAI6nB,GAAOjB,CACX,IAAIiB,EAGF,IAFA,GAAIC,GAAY3D,EAAK,GACnB4D,EAAKF,EAAK7nB,OAAS,EACT+nB,EAAL5D,GACL2D,EAAaD,EAAK1D,GAAM,GACxBphB,GAAO,OAAU0X,EAAGrC,WAAW0P,GAAe,YAAc,EAAS,KAI3E,GAAIrN,EAAGlK,KAAK0R,IAAMyF,GAAmBA,EAAgB1nB,OAAQ,CAC3D,GAAIgoB,GAAON,CACX,IAAIM,EAGF,IAFA,GAAIC,GAAa9D,EAAK,GACpB+D,EAAKF,EAAKhoB,OAAS,EACTkoB,EAAL/D,GACL8D,EAAcD,EAAK7D,GAAM,GACzBphB,GAAO,OAAU0X,EAAGrC,WAAW6P,GAAgB,YAAc,EAAS,KAI5EllB,GAAO,uBAAyB,EAAS,OAE3C,GAAyB,OAArBmkB,EACFnkB,GAAO,WAAa,EAAU,OAAS,EAAS,UAC3C,CACL,GAAIiiB,GAAoBvK,EAAGxC,UACvBkQ,EAAsB,UAAa9G,EAAO,MAI9C,IAHI5G,EAAGlK,KAAK8U,yBACV5K,EAAGxC,UAAYwC,EAAGnR,KAAK6W,YAAY1F,EAAGxC,UAAW,MAAQoJ,EAAM5G,EAAGlK,KAAK8P,eAErE2G,EACF,GAAIE,EACFnkB,GAAO,WAAa,EAAU,OAAS,EAAS,UAC3C,CACLA,GAAO,SAAYihB,EAAS,MAAI,YAChC,IAAI+B,GAAqBpE,CACzBA,GAAiBlH,EAAGzC,cAAgB,uBACpC,IAAImL,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,wBAA0B,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,uCAAyC,EAAwB,OACrOA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,wDAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,mDAAsD0X,EAAa,WAAI,YAAc,EAAU,KAExG1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnCD,EAAiBoE,EACbnE,IACF7e,GAAO,gBAGN,IAAIkkB,EACT,GAAyB,WAArBC,EAAgC,CAClCnkB,GAAO,QAAU,EAAU,cAC3B,IAAI0hB,GAAgBhK,EAAG+I,aACvB/I,GAAG+I,cAAgBQ,EAAIR,eAAgB,EACvCQ,EAAIzU,OAASsX,EACb7C,EAAIjM,WAAa0C,EAAG1C,WAAa,wBACjCiM,EAAIhM,cAAgByC,EAAGzC,cAAgB,wBACvCgM,EAAI/L,UAAYwC,EAAGlK,KAAK8U,uBAAyB5K,EAAGxC,UAAYwC,EAAGnR,KAAK6W,YAAY1F,EAAGxC,UAAW,MAAQoJ,EAAM5G,EAAGlK,KAAK8P,aACxH,IAAI2F,GAAYrF,EAAQ,OAASU,EAAO,GACpC5G,GAAGlK,KAAK0R,KAAI+B,EAAI5B,YAAYuD,GAAY,MAAQtE,EACpD,IAAI4E,GAAQxL,EAAG/J,SAASsT,EAEtBjhB,IADE0X,EAAGnR,KAAK+V,cAAc4G,EAAOL,GAAa,EACrC,IAAOnL,EAAGnR,KAAKiW,WAAW0G,EAAOL,EAAWI,GAAc,IAE1D,QAAU,EAAc,MAAQ,EAAc,KAAO,EAAU,IAExEjjB,GAAO,cAAiBihB,EAAS,MAAI,gBAAkB,EAAU,wHAA0H,EAAU,OAAS,EAAS,SACvNvJ,EAAG+I,cAAgBQ,EAAIR,cAAgBiB,MAClC,CACLT,EAAIzU,OAASsX,EACb7C,EAAIjM,WAAa0C,EAAG1C,WAAa,wBACjCiM,EAAIhM,cAAgByC,EAAGzC,cAAgB,wBACvCgM,EAAI/L,UAAYwC,EAAGlK,KAAK8U,uBAAyB5K,EAAGxC,UAAYwC,EAAGnR,KAAK6W,YAAY1F,EAAGxC,UAAW,MAAQoJ,EAAM5G,EAAGlK,KAAK8P,aACxH,IAAI2F,GAAYrF,EAAQ,OAASU,EAAO,GACpC5G,GAAGlK,KAAK0R,KAAI+B,EAAI5B,YAAYuD,GAAY,MAAQtE,EACpD,IAAI4E,GAAQxL,EAAG/J,SAASsT,EAEtBjhB,IADE0X,EAAGnR,KAAK+V,cAAc4G,EAAOL,GAAa,EACrC,IAAOnL,EAAGnR,KAAKiW,WAAW0G,EAAOL,EAAWI,GAAc,IAE1D,QAAU,EAAc,MAAQ,EAAc,KAAO,EAAU,IAEpEpE,IACF7e,GAAO,cAAiBihB,EAAS,MAAI,aAI3CvJ,EAAGxC,UAAY+M,EAEb+B,IACFhkB,GAAO,OAETA,GAAO,OACH6e,IACF7e,GAAO,aAAgBihB,EAAS,MAAI,OACpC9B,GAAkB,KAGtB,GAAIkG,GAAe3N,EAAGlK,KAAK8X,cAAgB5N,EAAG+I,aAC9C,IAAIiD,EAAYzmB,OAAQ,CACtB,GAAIsoB,GAAO7B,CACX,IAAI6B,EAGF,IAFA,GAAIX,GAAcY,EAAK,GACrBC,EAAKF,EAAKtoB,OAAS,EACTwoB,EAALD,GAAS,CACdZ,EAAeW,EAAKC,GAAM,EAC1B,IAAIrE,GAAOzC,EAAQkG,EACnB,IAAIlN,EAAGnR,KAAK4W,eAAegE,EAAMzJ,EAAGvC,MAAMwF,KAAM,CAC9C,GAAIwH,IAAQzK,EAAGnR,KAAK0V,YAAY2I,GAC9B3B,EAAYrF,EAAQuE,GACpBuD,GAAcL,GAAiC1gB,SAAjBwc,EAAAA,UAChCF,GAAIzU,OAAS2U,EACbF,EAAIjM,WAAa2J,EAAcwD,GAC/BlB,EAAIhM,cAAgB2J,EAAiB,IAAMlH,EAAGnR,KAAK6T,eAAewK,GAClE3D,EAAI/L,UAAYwC,EAAGnR,KAAKkX,QAAQ/F,EAAGxC,UAAW0P,EAAclN,EAAGlK,KAAK8P,cAChE5F,EAAGlK,KAAK0R,KAAI+B,EAAI5B,YAAYuD,GAAYlL,EAAGnR,KAAK6Q,eAAewN,GACnE,IAAI1B,GAAQxL,EAAG/J,SAASsT,EACxB,IAAIvJ,EAAGnR,KAAK+V,cAAc4G,EAAOL,GAAa,EAAG,CAC/CK,EAAQxL,EAAGnR,KAAKiW,WAAW0G,EAAOL,EAAWI,EAC7C,IAAI0C,IAAW1C,MACV,CACL,GAAI0C,IAAW9C,CACf7iB,IAAO,QAAU,EAAc,MAAQ,EAAc,KAEvD,GAAI0lB,GACF1lB,GAAO,IAAM,EAAU,QAClB,CACL,GAAIwkB,GAAiBA,EAAcI,GAAe,CAChD5kB,GAAO,QAAU,GAAa,0BAA6BihB,EAAS,MAAI,YACxE,IAAIgB,GAAoBvK,EAAGxC,UACzB8N,EAAqBpE,EACrByD,GAAmB3K,EAAGnR,KAAK6V,aAAawI,EACtClN,GAAGlK,KAAK8U,yBACV5K,EAAGxC,UAAYwC,EAAGnR,KAAKkX,QAAQwE,EAAmB2C,EAAclN,EAAGlK,KAAK8P,eAE1EsB,EAAiBlH,EAAGzC,cAAgB,WACpC,IAAImL,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,YAAc,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,oCAAsC,GAAqB,OACnNA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,gBAELA,GADE0X,EAAGlK,KAAK8U,uBACH,yBAEA,oCAAuC,GAAqB,MAErEtiB,GAAO,MAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnCD,EAAiBoE,EACjBtL,EAAGxC,UAAY+M,EACfjiB,GAAO,iBAGLA,IADE6e,EACK,QAAU,GAAa,0BAA6BoC,EAAS,MAAI,qBAEjE,QAAU,GAAa,oBAGlCjhB,IAAO,IAAM,EAAU,OAGvB6e,IACF7e,GAAO,aAAgBihB,EAAS,MAAI,OACpC9B,GAAkB,MAK1B,GAAIyG,IAAO/B,CACX,IAAI+B,GAGF,IAFA,GAAIb,GAAYc,GAAK,GACnBC,GAAKF,GAAK3oB,OAAS,EACT6oB,GAALD,IAAS,CACdd,EAAaa,GAAKC,IAAM,EACxB,IAAI1E,GAAOwC,EAAaoB,EACxB,IAAIrN,EAAGnR,KAAK4W,eAAegE,EAAMzJ,EAAGvC,MAAMwF,KAAM,CAC9CsG,EAAIzU,OAAS2U,EACbF,EAAIjM,WAAa0C,EAAG1C,WAAa,qBAAuB0C,EAAGnR,KAAK0V,YAAY8I,GAC5E9D,EAAIhM,cAAgByC,EAAGzC,cAAgB,sBAAwByC,EAAGnR,KAAK6T,eAAe2K;AACtF/kB,GAAO,gBAAkB,EAAS,OAAS,EAAU,WAAc0X,EAAGrC,WAAW0P,GAAe,YAAc,EAAS,QACvH9D,EAAI/L,UAAYwC,EAAGnR,KAAK6W,YAAY1F,EAAGxC,UAAW,MAAQoJ,EAAM5G,EAAGlK,KAAK8P,aACxE,IAAI2F,GAAYrF,EAAQ,OAASU,EAAO,GACpC5G,GAAGlK,KAAK0R,KAAI+B,EAAI5B,YAAYuD,GAAY,MAAQtE,EACpD,IAAI4E,GAAQxL,EAAG/J,SAASsT,EAEtBjhB,IADE0X,EAAGnR,KAAK+V,cAAc4G,EAAOL,GAAa,EACrC,IAAOnL,EAAGnR,KAAKiW,WAAW0G,EAAOL,EAAWI,GAAc,IAE1D,QAAU,EAAc,MAAQ,EAAc,KAAO,EAAU,IAEpEpE,IACF7e,GAAO,cAAiBihB,EAAS,MAAI,aAEvCjhB,GAAO,MACH6e,IACF7e,GAAO,cAAiBihB,EAAS,MAAI,aAEvCjhB,GAAO,OACH6e,IACF7e,GAAO,aAAgBihB,EAAS,MAAI,OACpC9B,GAAkB,MAK1B,GAAIzH,EAAGlK,KAAK0R,GAAI,CACd,GAAI6G,IAAOpB,CACX,IAAIoB,GAGF,IAFA,GAAIb,GAAac,GAAK,GACpBC,GAAKF,GAAK9oB,OAAS,EACTgpB,GAALD,IAAS,CACdd,EAAca,GAAKC,IAAM,EACzB,IAAIE,IAAYzB,EAAcS,GAC5B/D,EAAO+E,GAAU1Z,MACnB,IAAIkL,EAAGnR,KAAK4W,eAAegE,EAAMzJ,EAAGvC,MAAMwF,KAAM,CAC9CsG,EAAIzU,OAAS2U,EACbF,EAAIjM,WAAa0C,EAAG1C,WAAa,iBAAmB0C,EAAGnR,KAAK0V,YAAYiJ,GAAe,UACvFjE,EAAIhM,cAAgByC,EAAGzC,cAAgB,kBAAoByC,EAAGnR,KAAK6T,eAAe8K,GAAe,UACjGllB,GAAO,mBAAqB,EAAS,qBAAuB,EAAS,OAAS,EAAU,WAAc0X,EAAGrC,WAAW6P,GAAgB,YAAc,EAAS,mBAAqB,EAAS,OACzLjE,EAAI/L,UAAYwC,EAAGnR,KAAK6W,YAAY1F,EAAGxC,UAAW,MAAQoJ,EAAM5G,EAAGlK,KAAK8P,aACxE,IAAI2F,GAAYrF,EAAQ,OAASU,EAAO,GACpC5G,GAAGlK,KAAK0R,KAAI+B,EAAI5B,YAAYuD,GAAY,MAAQtE,EACpD,IAAI4E,GAAQxL,EAAG/J,SAASsT,EAEtBjhB,IADE0X,EAAGnR,KAAK+V,cAAc4G,EAAOL,GAAa,EACrC,IAAOnL,EAAGnR,KAAKiW,WAAW0G,EAAOL,EAAWI,GAAc,IAE1D,QAAU,EAAc,MAAQ,EAAc,KAAO,EAAU,IAEpEpE,IACF7e,GAAO,cAAiBihB,EAAS,MAAI,aAEvCjhB,GAAO,MACH6e,IACF7e,GAAO,cAAiBihB,EAAS,MAAI,aAEvCjhB,GAAO,OACH6e,IACF7e,GAAO,aAAgBihB,EAAS,MAAI,OACpC9B,GAAkB,IAEpB,IAAIgH,IAASD,GAAUpX,QACrBsX,GAASF,GAAUrX,OACrB,IAAelK,SAAXwhB,IAAmCxhB,SAAXyhB,GAAsB,CAChDpmB,GAAO,QAAU,EAAW,WAC5B,IAAIgjB,GAAqBpE,CACzB,IAAeja,SAAXwhB,GAAsB,CACxB,GAAIE,IAASF,GACXG,GAAU,UACVC,GAAc,MAChBvmB,IAAO,IAAM,EAAW,iBAAmB,EAAS,OAAS,GAAW,KACxE4e,EAAiBlH,EAAGzC,cAAgB,yBACpCjV,GAAO,UAAY,EAAW,QAC9B,IAAIogB,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,iBAAmB,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,2BAA6B,GAAY,aAAgB,GAAW,eAAmBA,EAAGnR,KAAK6V,aAAa8I,GAAgB,OACzRxN,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,gCAAmC,GAAgB,SAAW,GAAW,iCAAoC0X,EAAGnR,KAAK6V,aAAa8I,GAAgB,QAEvJxN,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,MACQ2E,SAAXyhB,KACFpmB,GAAO,UAGX,GAAe2E,SAAXyhB,GAAsB,CACxB,GAAIC,IAASD,GACXE,GAAU,UACVC,GAAc,MAChBvmB,IAAO,IAAM,EAAW,iBAAmB,EAAS,OAAS,GAAW,KACxE4e,EAAiBlH,EAAGzC,cAAgB,yBACpCjV,GAAO,UAAY,EAAW,QAC9B,IAAIogB,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,iBAAmB,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,2BAA6B,GAAY,aAAgB,GAAW,eAAmBA,EAAGnR,KAAK6V,aAAa8I,GAAgB,OACzRxN,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,gCAAmC,GAAgB,SAAW,GAAW,iCAAoC0X,EAAGnR,KAAK6V,aAAa8I,GAAgB,QAEvJxN,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,MAET4e,EAAiBoE,EACbnE,IACF7e,GAAO,QAAU,EAAW,OAC5Bmf,GAAkB,QAW9B,MAJIN,KACF7e,GAAO,IAAM,EAAmB,QAAU,EAAU,iBAEtDA,EAAM0X,EAAGnR,KAAKmW,YAAY1c,SAItBwmB,IAAI,SAAS7pB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAAsBic,EAAI0G,GACzC,GAKIC,GALAre,EAAM,IACNwe,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,GAClC,IAAe,KAAXE,GAA6B,MAAXA,EAChBhH,EAAG9C,QACL5U,GAAO,oBAAkC,EAAU,qBAC/B,MAAhB0X,EAAGxC,YACLlV,GAAO,MAAS0X,EAAY,WAE9B1X,GAAO,qIACH6e,IACF7e,GAAO,cAGTA,GAAO,0BAAwC,EAAU,qBACrC,MAAhB0X,EAAGxC,YACLlV,GAAO,MAAS0X,EAAY,WAE9B1X,GAAO,iJACH6e,IACF7e,GAAO,iBAGN,CACL,GAAIymB,GAAU/O,EAAGtC,WAAWsC,EAAGlD,OAAQkK,EAAShH,EAAG9C,OACnD,IAAgBjQ,SAAZ8hB,EAAuB,CACzB,GAAIC,GAAW,2BAA8BhI,EAAU,YAAchH,EAAGlD,MACxE,IAA2B,QAAvBkD,EAAGlK,KAAKmZ,YAAuB,CACjCxQ,QAAQE,IAAIqQ,EACZ,IAAItG,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,QAAU,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,wBAA2BA,EAAGnR,KAAK6V,aAAasC,GAAY,OAChNhH,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,0CAA+C0X,EAAGnR,KAAK6V,aAAasC,GAAY,MAErFhH,EAAGlK,KAAK+S,UACVvgB,GAAO,cAAiB0X,EAAGnR,KAAK6Q,eAAesH,GAAY,mCAAsChH,EAAa,WAAI,YAAc,EAAU,KAE5I1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAE/BA,IACF7e,GAAO,sBAEJ,CAAA,GAA2B,UAAvB0X,EAAGlK,KAAKmZ,YAKZ,CACL,GAAIC,GAAS,GAAI/pB,OAAM6pB,EAGvB,MAFAE,GAAOvZ,WAAaqK,EAAG3Q,QAAQX,IAAIsR,EAAGlD,OAAQkK,GAC9CkI,EAAOxZ,cAAgBsK,EAAG3Q,QAAQkS,YAAYvB,EAAG3Q,QAAQoT,SAASyM,EAAOvZ,aACnEuZ,EARNzQ,QAAQE,IAAIqQ,GACR7H,IACF7e,GAAO,sBAQN,IAAsB,gBAAXymB,GAChBzmB,GAAO,WAAa,EAAY,IAAM,EAAU,qBAC5B,MAAhB0X,EAAGxC,YACLlV,GAAO,MAAS0X,EAAY,WAE9B1X,GAAO,yCAA2C,EAAY,0CAA4C,EAAY,wCAClH6e,IACF7e,GAAO,gBAEJ,CACL,GAAIihB,GAAMvJ,EAAGnR,KAAKiL,KAAKkG,EACvBuJ,GAAI1C,QACJ0C,EAAIzU,OAASia,EAAQja,OACrByU,EAAIjM,WAAa,GACjBiM,EAAIhM,cAAgByJ,CACpB,IAAIwE,GAAQxL,EAAG/J,SAASsT,GAAKjjB,QAAQ,oBAAqByoB,EAAQ3pB,KAClEkD,IAAO,IAAM,EAAU,IACnB6e,IACF7e,GAAO,aAAgBihB,EAAS,MAAI,SAI1C,MAAOjhB,SAGH6mB,IAAI,SAASlqB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAA2Bic,EAAI0G,GAC9C,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BO,EAAS,QAAUT,EACnBwB,EAAUpI,EAAGlK,KAAK0R,IAAMR,EAAQd,MAChCmC,EAAeD,EAAUpI,EAAGnR,KAAKoX,QAAQe,EAAQd,MAAOY,EAAU9G,EAAG2H,aAAeX,CAKxF,IAJIoB,IACF9f,GAAO,cAAgB,EAAS,MAAQ,EAAiB,KACzD+f,EAAe,SAAWzB,IAEvBwB,EACH,GAAqBpI,EAAGlK,KAAK+W,aAAzB7F,EAAQzhB,QAAiCya,EAAGlL,OAAOiD,YAAcxM,OAAO8B,KAAK2S,EAAGlL,OAAOiD,YAAYxS,OAAQ,CAC7G,GAAIqnB,MACApD,EAAOxC,CACX,IAAIwC,EAGF,IAFA,GAAIa,GAAW8C,EAAK,GAClBxD,EAAKH,EAAKjkB,OAAS,EACTokB,EAALwD,GAAS,CACd9C,EAAYb,EAAK2D,GAAM,EACvB,IAAIiC,GAAepP,EAAGlL,OAAOiD,WAAWsS,EAClC+E,IAAgBpP,EAAGnR,KAAK4W,eAAe2J,EAAcpP,EAAGvC,MAAMwF,OAClE2J,EAAUA,EAAUrnB,QAAU8kB,QAKpC,IAAIuC,GAAY5F,CAGpB,IAAIoB,GAAWwE,EAAUrnB,OAAQ,CAC/B,GAAIglB,GAAoBvK,EAAGxC,UACzB6R,EAAgBjH,GAAWwE,EAAUrnB,QAAUya,EAAGlK,KAAK+W,YACzD,IAAI1F,EAEF,GADA7e,GAAO,eAAiB,EAAS,KAC7B+mB,EAAe,CACZjH,IACH9f,GAAO,cAAgB,EAAS,qBAAuB,EAAgB,KAEzE,IAAIohB,GAAK,IAAM9C,EACb8D,EAAgB,SAAW9D,EAAO,IAAM8C,EAAK,IAC7CiB,EAAmB,OAAUD,EAAgB,MAC3C1K,GAAGlK,KAAK8U,yBACV5K,EAAGxC,UAAYwC,EAAGnR,KAAK6W,YAAY6E,EAAmBG,EAAe1K,EAAGlK,KAAK8P,eAE/Etd,GAAO,QAAU,EAAW,YACxB8f,IACF9f,GAAO,cAAgB,EAAS,mBAAqB,EAAW,0CAA4C,EAAS,MAAQ,EAAW,oBAE1IA,GAAO,aAAe,EAAO,SAAW,EAAO,YAAc,EAAS,YAAc,EAAO,SAAW,EAAW,MAAQ,EAAU,UAAY,EAAS,IAAM,EAAO,0BAA4B,EAAW,cACxM8f,IACF9f,GAAO,SAETA,GAAO,UAAY,EAAW,QAC9B,IAAIogB,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,YAAc,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,oCAAsC,EAAqB,OACnNA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,gBAELA,GADE0X,EAAGlK,KAAK8U,uBACH,yBAEA,oCAAuC,EAAqB,MAErEtiB,GAAO,MAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,iBACF,CACLA,GAAO,QACP,IAAI8kB,GAAOR,CACX,IAAIQ,EAGF,IAFA,GAAI5C,GAAYd,EAAK,GACnB4D,EAAKF,EAAK7nB,OAAS,EACT+nB,EAAL5D,GAAS,CACdc,EAAa4C,EAAK1D,GAAM,GACpBA,IACFphB,GAAO,OAET,IAAImiB,GAAQzK,EAAGnR,KAAK0V,YAAYiG,EAChCliB,IAAO,MAAQ,EAAU,EAAU,6BAA+B,EAAS,MAAS0X,EAAGnR,KAAK6Q,eAAeM,EAAGlK,KAAK8P,aAAe4E,EAAaC,GAAU,OAG7JniB,GAAO,OACP,IAAIoiB,GAAgB,UAAY9D,EAC9B+D,EAAmB,OAAUD,EAAgB,MAC3C1K,GAAGlK,KAAK8U,yBACV5K,EAAGxC,UAAYwC,EAAGlK,KAAK8P,aAAe5F,EAAGnR,KAAK6W,YAAY6E,EAAmBG,GAAe,GAAQH,EAAoB,MAAQG,EAElI,IAAIhC,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,YAAc,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,oCAAsC,EAAqB,OACnNA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,gBAELA,GADE0X,EAAGlK,KAAK8U,uBACH,yBAEA,oCAAuC,EAAqB,MAErEtiB,GAAO,MAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,iBAGT,IAAI+mB,EAAe,CACZjH,IACH9f,GAAO,cAAgB,EAAS,qBAAuB,EAAgB,KAEzE,IAAIohB,GAAK,IAAM9C,EACb8D,EAAgB,SAAW9D,EAAO,IAAM8C,EAAK,IAC7CiB,EAAmB,OAAUD,EAAgB,MAC3C1K,GAAGlK,KAAK8U,yBACV5K,EAAGxC,UAAYwC,EAAGnR,KAAK6W,YAAY6E,EAAmBG,EAAe1K,EAAGlK,KAAK8P,eAE3EwC,IACF9f,GAAO,cAAgB,EAAS,4BAA8B,EAAS,qBACnE0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,YAAc,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,oCAAsC,EAAqB,OACnNA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,gBAELA,GADE0X,EAAGlK,KAAK8U,uBACH,yBAEA,oCAAuC,EAAqB,MAErEtiB,GAAO,MAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,OAETA,GAAO,gGAAkG,EAAS,sBAEpHA,GAAO,aAAe,EAAO,SAAW,EAAO,YAAc,EAAS,YAAc,EAAO,aAAe,EAAU,UAAY,EAAS,IAAM,EAAO,oCAClJ0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,YAAc,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,oCAAsC,EAAqB,OACnNA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,gBAELA,GADE0X,EAAGlK,KAAK8U,uBACH,yBAEA,oCAAuC,EAAqB,MAErEtiB,GAAO,MAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,OAETA,GAAO,mFACH8f,IACF9f,GAAO,aAEJ,CACL,GAAIilB,GAAOX,CACX,IAAIW,EAGF,IAFA,GAAIlD,GAAWX,EAAK,GAClB+D,EAAKF,EAAKhoB,OAAS,EACTkoB,EAAL/D,GAAS,CACdW,EAAYkD,EAAK7D,GAAM,EACvB,IAAIe,GAAQzK,EAAGnR,KAAK0V,YAAY8F,GAC9BM,EAAmB3K,EAAGnR,KAAK6V,aAAa2F,EACtCrK,GAAGlK,KAAK8U,yBACV5K,EAAGxC,UAAYwC,EAAGnR,KAAKkX,QAAQwE,EAAmBF,EAAWrK,EAAGlK,KAAK8P,eAEvEtd,GAAO,QAAU,EAAU,EAAU,kCACjC0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,YAAc,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,oCAAsC,EAAqB,OACnNA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,gBAELA,GADE0X,EAAGlK,KAAK8U,uBACH,yBAEA,oCAAuC,EAAqB,MAErEtiB,GAAO,MAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,OAETA,GAAO,kFAKf0X,EAAGxC,UAAY+M,MACNpD,KACT7e,GAAO,eAET,OAAOA,SAGHgnB,IAAI,SAASrqB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAAyBic,EAAI0G,GAC5C,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BO,EAAS,QAAUT,EACnBiD,EAAQ,SAAWjD,EACnB2C,EAAMvJ,EAAGnR,KAAKiL,KAAKkG,GACnByH,EAAiB,EACrB8B,GAAI1C,OACJ,IACE0I,GADEC,EAAY,WAAaxP,EAAG6G,KAEhCve,IAAO,OAAS,EAAc,GAC9B,IAAIkhB,GAAOxC,CACX,IAAIwC,EAGF,IAFA,GAAIC,GAAMgG,EAAa,GACrB9F,EAAKH,EAAKjkB,OAAS,EACDokB,EAAb8F,GAAiB,CAMtB,GALAhG,EAAOD,EAAKiG,GAAc,GACtBA,IAAeF,IACjBjnB,GAAO,SAAW,EAAc,OAChCmf,GAAkB,KAEhBgC,EAAAA,OAAWzJ,EAAGnR,KAAK4W,eAAegE,EAAAA,MAASzJ,EAAGvC,MAAMwF,KAAM,CAC5D3a,GAAO,QAAU,EAAU,eAC3B,IAAI0hB,GAAgBhK,EAAG+I,aAUvB,IATA/I,EAAG+I,cAAgBQ,EAAIR,eAAgB,EACvCQ,EAAIZ,cAAe,EACnBY,EAAIzU,OAAS2U,EAAAA,MACbF,EAAIjM,WAAa2J,EAAc,IAAMwI,EAAa,OAClDlG,EAAIhM,cAAgB2J,EAAiB,IAAMuI,EAAa,MACxDnnB,GAAO,IAAO0X,EAAG/J,SAASsT,GAAQ,IAClCA,EAAIZ,cAAe,EACnB3I,EAAG+I,cAAgBQ,EAAIR,cAAgBiB,EACvC1hB,GAAO,IAAM,EAAc,WAAcihB,EAAS,MAAI,SAAW,EAAc,QACvD,iBAAbE,GAAKiG,KAAmB,CACjC,GAAIjG,EAAKiG,QAAS,EAAO,CACvB,GAAIhH,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,UAAY,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,4BAA8B,EAAe,MACnMA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,4DAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAGrC7e,GAAO,aAAgBihB,EAAS,MAAI,MAASE,EAAS,KAAI,SAE1DF,GAAIzU,OAAS2U,EAAKiG,KAClBnG,EAAIjM,WAAa2J,EAAc,IAAMwI,EAAa,SAClDlG,EAAIhM,cAAgB2J,EAAiB,IAAMuI,EAAa,QACxDnnB,GAAO,IAAO0X,EAAG/J,SAASsT,GAAQ,GAEpCjhB,IAAO,wBAA0B,EAAU,iCAAmC,EAAU,sBAAwB,EAAU,kCAG1H,IADAA,GAAO,IAAM,EAAc,aACH,iBAAbmhB,GAAKiG,KAAmB,CACjC,GAAIjG,EAAKiG,QAAS,EAAO,CACvB,GAAIhH,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,UAAY,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,4BAA8B,EAAe,MACnMA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,4DAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAGrC7e,GAAO,aAAgBihB,EAAS,MAAI,MAASE,EAAS,KAAI,SAE1DF,GAAIzU,OAAS2U,EAAKiG,KAClBnG,EAAIjM,WAAa2J,EAAc,IAAMwI,EAAa,SAClDlG,EAAIhM,cAAgB2J,EAAiB,IAAMuI,EAAa,QACxDnnB,GAAO,IAAO0X,EAAG/J,SAASsT,GAAQ,GAGtCgG,GAAkB9F,EAAAA,YAKtB,MAFAnhB,IAAO,GAAK,EAAmB,OAAS,EAAW,WAAcihB,EAAS,MAAI,KAC9EjhB,EAAM0X,EAAGnR,KAAKmW,YAAY1c,SAItBqnB,IAAI,SAAS1qB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAA8Bic,EAAI0G,GACjD,GAOIC,GAPAre,EAAM,IACNse,EAAO5G,EAAG6G,MACVC,EAAW9G,EAAG+G,UACdC,EAAUhH,EAAGlL,OAAO4R,GACpBO,EAAcjH,EAAG1C,WAAa,IAAMoJ,EACpCQ,EAAiBlH,EAAGzC,cAAgB,IAAMmJ,EAC1CS,GAAiBnH,EAAGlK,KAAKsR,UAEzBlB,EAAQ,QAAUY,GAAY,IAC9BO,EAAS,QAAUT,EACnBwB,EAAUpI,EAAGlK,KAAK0R,IAAMR,EAAQd,MAChCmC,EAAeD,EAAUpI,EAAGnR,KAAKoX,QAAQe,EAAQd,MAAOY,EAAU9G,EAAG2H,aAAeX,CAKxF,IAJIoB,IACF9f,GAAO,cAAgB,EAAS,MAAQ,EAAiB,KACzD+f,EAAe,SAAWzB,IAEvBI,GAAWoB,IAAYpI,EAAGlK,KAAKmC,eAAgB,EAAO,CACrDmQ,IACF9f,GAAO,QAAU,EAAW,SAAW,EAAiB,iBAAmB,EAAiB,mBAAqB,EAAW,4BAA8B,EAAiB,kBAAsB,EAAW,qBAE9MA,GAAO,QAAU,EAAW,gBAAkB,EAAU,0BAA4B,EAAU,kEAAoE,EAAU,QAAU,EAAU,WAAa,EAAW,kCACpN8f,IACF9f,GAAO,SAETA,GAAO,SAAW,EAAW,QAC7B,IAAIogB,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,eAAiB,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,8BAC3JA,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,mGAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,eAELA,GADE8f,EACK,kBAAoB,EAEpB,GAAK,EAEd9f,GAAO,2CAA8C0X,EAAa,WAAI,YAAc,EAAU,KAEhG1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,MACH6e,IACF7e,GAAO,gBAGL6e,KACF7e,GAAO,gBAGX,OAAOA,SAGHsnB,IAAI,SAAS3qB,EAAQjB,EAAOD,GAClC,YACAC,GAAOD,QAAU,SAA2Bic,EAAI0G,GA2U9C,QAASmJ,GAAgBC,GACvB,IAAK,GAAI5qB,GAAI,EAAO4qB,EAAY9M,MAAMzd,OAAtBL,EAA8BA,IAC5C,GAAI6qB,EAAeD,EAAY9M,MAAM9d,IAAK,OAAO,EAGrD,QAAS6qB,GAAeC,GACtB,MAAoC/iB,UAA7B+S,EAAGlL,OAAOkb,EAAM3P,UAA4C,cAAjB2P,EAAM3P,UAA4BL,EAAGlL,OAAOuX,wBAAyB,GAAkD,gBAAlCrM,GAAGlL,OAAOuX,sBAAqCrM,EAAGlL,OAAOoX,mBAAqB3gB,OAAO8B,KAAK2S,EAAGlL,OAAOoX,mBAAmB3mB,QAAYya,EAAGlK,KAAK0R,IAAMxH,EAAGlL,OAAOkY,eAAiBzhB,OAAO8B,KAAK2S,EAAGlL,OAAOkY,eAAeznB,QAhV1V,GAAI+C,GAAM,EACV,IAAI0X,EAAG3C,MAAO,CACZ,GAAI4S,GAAOjQ,EAAG3C,MACZuJ,EAAO5G,EAAG6G,MAAQ,EAClBC,EAAW9G,EAAG+G,UAAY,EAC1Bb,EAAQ,MACVlG,GAAGkQ,OAASlQ,EAAG3Q,QAAQoT,SAASzC,EAAGva,KAAKqP,OAAOwM,IAC/CtB,EAAGlD,OAASkD,EAAGlD,QAAUkD,EAAGkQ,aACrBlQ,GAAG3C,MACN2C,EAAGlK,KAAK0R,KAAIxH,EAAG2H,aAAe1a,SAClC3E,GAAO,6EACPA,GAAO,4BACF,CACL,GAAIse,GAAO5G,EAAG6G,MACZC,EAAW9G,EAAG+G,UACdb,EAAQ,QAAUY,GAAY,GAC5B9G,GAAGlL,OAAOwM,KAAItB,EAAGlD,OAASkD,EAAG3Q,QAAQX,IAAIsR,EAAGlD,OAAQkD,EAAGlL,OAAOwM,KAClEhZ,GAAO,aAAe,EAAS,aAEjC,GAIEqe,GAJEU,EAAS,QAAUT,EACrBO,GAAiBnH,EAAGlK,KAAKsR,UACzB+I,EAAkB,GAClBC,EAAkB,GAEhBC,EAAcrQ,EAAGlL,OAAOnP,KACxB6jB,EAAOxJ,EAAGvC,KACd,IAAI+L,EAGF,IAFA,GAAIsG,GAAa3C,EAAK,GACpBxD,EAAKH,EAAKjkB,OAAS,EACTokB,EAALwD,GAEL,GADA2C,EAActG,EAAK2D,GAAM,GACrB0C,EAAgBC,GAAc,CAIhC,GAHIA,EAAYnqB,OACd2C,GAAO,QAAW0X,EAAGnR,KAAK6U,cAAcoM,EAAYnqB,KAAMugB,GAAU,QAElElG,EAAGlK,KAAK8X,cAAgB5N,EAAG+I,cAC7B,GAAwB,UAApB+G,EAAYnqB,MAAoBqa,EAAGlL,OAAOiD,WAAY,CACxD,GAAIiP,GAAUhH,EAAGlL,OAAOiD,WACtBiU,EAAczgB,OAAO8B,KAAK2Z,GACxBoG,EAAOpB,CACX,IAAIoB,EAGF,IAFA,GAAIF,GAAcoD,EAAK,GACrBhD,EAAKF,EAAK7nB,OAAS,EACT+nB,EAALgD,GAAS,CACdpD,EAAeE,EAAKkD,GAAM,EAC1B,IAAI7G,GAAOzC,EAAQkG,EACnB,IAAqBjgB,SAAjBwc,EAAAA,WAA4B,CAC9B,GAAI8B,GAAYrF,EAAQlG,EAAGnR,KAAK0V,YAAY2I,EAC5C5kB,IAAO,SAAW,EAAc,mBAAqB,EAAc,MAAS0X,EAAGpC,WAAW6L,EAAAA,YAAiB,WAI5G,IAAwB,SAApBqG,EAAYnqB,MAAmB8G,MAAMD,QAAQwT,EAAGlL,OAAOoC,OAAQ,CACxE,GAAIqW,GAAOvN,EAAGlL,OAAOoC,KACrB,IAAIqW,EAGF,IAFA,GAAI9D,GAAMC,EAAK,GACb+D,EAAKF,EAAKhoB,OAAS,EACTkoB,EAAL/D,GAEL,GADAD,EAAO8D,EAAK7D,GAAM,GACGzc,SAAjBwc,EAAAA,WAA4B,CAC9B,GAAI8B,GAAYrF,EAAQ,IAAMwD,EAAK,GACnCphB,IAAO,SAAW,EAAc,mBAAqB,EAAc,MAAS0X,EAAGpC,WAAW6L,EAAAA,YAAiB,MAMrH,GAAIoE,GAAOiC,EAAY9M,KACvB,IAAI6K,EAGF,IAFA,GAAImC,GAAOlC,EAAK,GACdC,EAAKF,EAAKtoB,OAAS,EACTwoB,EAALD,GAEL,GADAkC,EAAQnC,EAAKC,GAAM,GACfiC,EAAeC,GAAQ,CACzB,GAAIA,EAAMO,OAAQ,CAChB,GAAIvJ,GAAUhH,EAAGlL,OAAOkb,EAAM3P,SAC5BmQ,EAAgBxQ,EAAGnC,cAAcmS,EAAOhJ,EAAShH,EAAGlL,OAAQkL,GAC5DyQ,EAAYD,EAAcprB,KAAO,UACjC6hB,EAAcjH,EAAG1C,WAAa,IAAM0S,EAAM3P,QAC1C6G,EAAiBlH,EAAGzC,cAAgB,IAAMyS,EAAM3P,QAChDwJ,EAAQ,OAASjD,EACjB8C,EAAK,IAAM9C,EACX8J,EAAW,UAAY9J,EACvB+J,EAAQX,EAAM/P,WACd2Q,EAAUD,EAAMzQ,OAChB2Q,EAASF,EAAMxQ,KAKjB,IAJMyQ,GAAWC,IACfvoB,GAAO,GAAK,EAAc,YAE5BA,GAAO,OAAS,EAAU,aACtBsoB,GAAWD,EAAMG,WACnBxoB,GAAO,IAAOkoB,EAAsB,aAC/B,IAAIK,EAAQ,CACjB,GAAItH,GAAMvJ,EAAGnR,KAAKiL,KAAKkG,EACvBuJ,GAAI1C,QACJ0C,EAAIzU,OAAS0b,EAAcva,SAC3BsT,EAAIjM,WAAa,EACjB,IAAI0M,GAAgBhK,EAAG+I,aACvB/I,GAAG+I,cAAgBQ,EAAIR,eAAgB,CACvC,IAAIyC,GAAQxL,EAAG/J,SAASsT,GAAKjjB,QAAQ,oBAAqBkqB,EAAcprB,KACxE4a,GAAG+I,cAAgBQ,EAAIR,cAAgBiB,EACvC1hB,GAAO,IAAM,EAEfA,GAAO,SACHsoB,EAEAtoB,GADEqoB,EAAMG,WACD,SAAW,EAAS,IAEpB,KAAQN,EAAsB,SAAI,KAElCK,EACTvoB,GAAO,SAAYihB,EAAS,MAAI,KAEhCjhB,GAAO,IAAOkoB,EAAkB,KAAI,cAChCG,EAAMxa,QACR7N,GAAO,MAAQ,EAAU,KAEzBA,GAAO,qBAAuB,EAAgB,MAAQ,EAAU,IAC5DkoB,EAAcva,SAAS1Q,OAAS,IAClC+C,GAAO,qBAAwB0X,EAAa,WAAI,MAGpD1X,GAAO,OAETA,GAAO,OACPqe,EAAgBqJ,EAAM3P,OACtB,IAAIqI,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,EACN,IAAIogB,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,UAAY,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,4BAA+BgQ,EAAa,QAAI,OACtMhQ,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,8BAAiC0nB,EAAa,QAAI,2BAEvDhQ,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,8EAEnC,IAAI4J,GAAkBzoB,CACtBA,GAAMogB,EAAWxU,MACb0c,EACED,EAAM9qB,OACY,QAAhB8qB,EAAM9qB,SACRyC,GAAO,cAAgB,EAAO,IAAM,EAAU,KAAO,EAAO,YAAc,EAAO,aAAe,EAAa,cAAgB,EAAO,UAAY,EAAa,8BAAgC,EAAa,kCAAuC0X,EAAY,UAAI,OAC7PA,EAAGlK,KAAK+S,UACVvgB,GAAO,IAAM,EAAa,4BAA8B,EAAgB,KAAO,EAAa,WAAa,EAAU,MAErHA,GAAO,OAGLqoB,EAAM9qB,UAAW,EACnByC,GAAO,IAAM,EAAoB,KAEjCA,GAAO,QAAU,EAAU,iBAAmB,EAAoB,uBAAyB,EAAO,IAAM,EAAU,KAAO,EAAO,YAAc,EAAO,aAAe,EAAa,cAAgB,EAAO,UAAY,EAAa,8BAAgC,EAAa,kCAAuC0X,EAAY,UAAI,OACjUA,EAAGlK,KAAK+S,UACVvgB,GAAO,IAAM,EAAa,4BAA8B,EAAgB,KAAO,EAAa,WAAa,EAAU,MAErHA,GAAO,SAGFuoB,GACTvoB,GAAO,kBACH0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,UAAY,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,4BAA+BgQ,EAAa,QAAI,OACtMhQ,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,8BAAiC0nB,EAAa,QAAI,2BAEvDhQ,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,OAETA,GAAO,gFACF0X,EAAG+I,eAAiB5B,IACvB7e,GAAO,+CAGTA,GAAO,sBAAwB,EAAc,wCAA0C,EAAc,yBAA2B,EAAc,yCAA2C,EAAO,IAAM,EAAU,KAAO,EAAO,YAAc,EAAO,aAAe,EAAa,cAAgB,EAAO,OAAS,EAAa,kCAAuC0X,EAAY,UAAI,MAC/WA,EAAGlK,KAAK+S,UACVvgB,GAAO,IAAM,EAAa,4BAA8B,EAAgB,KAAO,EAAa,WAAa,EAAU,MAErHA,GAAO,eAAiB,EAAoB,OAE9Cqe,EAAgB1Z,OAChB3E,GAAO,MACH6e,IACF7e,GAAO,gBAGTA,IAAO,IAAO0nB,EAAM5qB,KAAK4a,EAAIgQ,EAAM3P,SAAY,GAE7C8G,KACFgJ,GAAmB,KAS3B,GAJIhJ,IACF7e,GAAO,IAAM,EAAoB,IACjC6nB,EAAkB,IAEhBL,EAAYnqB,OACd2C,GAAO,MACH+nB,GAAeA,IAAgBP,EAAYnqB,MAAM,CACnD,GAAIqrB,IAAe,CACnB1oB,IAAO,UACP,IAAI2e,GAAcjH,EAAG1C,WAAa,QAChC4J,EAAiBlH,EAAGzC,cAAgB,QAClCmL,EAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,QAAU,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,yBAEtJ1X,GADE2oB,EACK,GAAMZ,EAAY3pB,KAAK,KAEvB,GAAK,EAEd4B,GAAO,OACH0X,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,0BAELA,GADE2oB,EACK,GAAMZ,EAAY3pB,KAAK,KAEvB,GAAK,EAEd4B,GAAO,MAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,MAGP6e,IACF7e,GAAO,mBAELA,GADE2nB,EACK,IAEA,QAAU,EAEnB3nB,GAAO,OACP8nB,GAAmB,KAK3B,GAAIC,IAAgBW,EAAc,CAChC,GAAI/J,GAAcjH,EAAG1C,WAAa,QAChC4J,EAAiBlH,EAAGzC,cAAgB,QACpC0T,EAAWxkB,MAAMD,QAAQ6jB,GACzBa,EAAUD,EAAW,iBAAmB,eAC1C3oB,IAAO,QAAW0X,EAAGnR,KAAKqiB,GAASb,EAAanK,GAAO,GAAS,QAChE,IAAIwC,GAAaA,KACjBA,GAAWzhB,KAAKqB,GAChBA,EAAM,GACF0X,EAAG2I,gBAAiB,GACtBrgB,GAAO,iBAAoBqe,GAAiB,QAAU,oCAA0C3G,EAAY,UAAI,mBAAqB,EAAmB,yBAEtJ1X,GADE2oB,EACK,GAAMZ,EAAY3pB,KAAK,KAEvB,GAAK,EAEd4B,GAAO,OACH0X,EAAGlK,KAAK8S,YAAa,IACvBtgB,GAAO,0BAELA,GADE2oB,EACK,GAAMZ,EAAY3pB,KAAK,KAEvB,GAAK,EAEd4B,GAAO,MAEL0X,EAAGlK,KAAK+S,UACVvgB,GAAO,6BAA+B,EAAgB,mCAAsC0X,EAAa,WAAI,YAAc,EAAU,KAEvI1X,GAAO,OAEPA,GAAO,MAET,IAAIwgB,GAAQxgB,CACZA,GAAMogB,EAAWxU,MAEf5L,IADG0X,EAAG+I,eAAiB5B,EAChB,uBAAyB,EAAU,oBAEnC,cAAgB,EAAU,+EAEnC7e,GAAO,KAyBT,MAvBI6e,KACF7e,GAAO,IAAM,EAAoB,KAE/B2nB,GACF3nB,GAAO,+BACPA,GAAO,+BACPA,GAAO,MAEPA,GAAO,QAAU,EAAW,sBAAwB,EAAS,IAE/DA,EAAM0X,EAAGnR,KAAKmW,YAAY1c,GACtB2nB,GAAQ9I,IACV7e,EAAM0X,EAAGnR,KAAKuW,iBAAiB9c,IAW1BA,QAGH6oB,IAAI,SAASlsB,EAAQjB,EAAOD,GAClC,YAEA,IAAIygB,GAAa,uBAOjBxgB,GAAOD,QAAU,SAAoBsc,EAASJ,GAwB5C,QAASmR,GAAS/Q,EAASsD,EAAU1D,GAEnC,IAAK,GADDoR,GACKnsB,EAAE,EAAKZ,EAAKmZ,MAAMlY,OAAbL,EAAqBA,IAAK,CACtC,GAAIosB,GAAKhtB,EAAKmZ,MAAMvY,EACpB,IAAIosB,EAAG3rB,MAAQge,EAAU,CACvB0N,EAAYC,CACZ,QAICD,IACHA,GAAc1rB,KAAMge,EAAUX,UAC9B1e,EAAKmZ,MAAMxW,KAAKoqB,GAGlB,IAAIvR,IAASO,QAASA,EAASJ,WAAYA,EAAYsQ,QAAQ,EAC/Dc,GAAUrO,MAAM/b,KAAK6Y,GAIvB,QAAS4D,GAAcC,GACrB,IAAKrf,EAAKmZ,MAAM0F,MAAMQ,GAAW,KAAM,IAAIxe,OAAM,gBAAkBwe,GA5CrE,GAAIrf,GAAOC,IACX,IAAIA,KAAKkZ,MAAMyF,SAAS7C,GACtB,KAAM,IAAIlb,OAAM,WAAakb,EAAU,sBAEzC,KAAKmE,EAAWxa,KAAKqW,GACnB,KAAM,IAAIlb,OAAM,WAAakb,EAAU,6BAEzC,IAAIJ,EAAY,CACd,GAAI0D,GAAW1D,EAAWta,IAC1B,IAAI8G,MAAMD,QAAQmX,GAAW,CAC3B,GAAIze,GAAG6G,EAAM4X,EAASpe,MACtB,KAAKL,EAAE,EAAK6G,EAAF7G,EAAOA,IAAKwe,EAAcC,EAASze,GAC7C,KAAKA,EAAE,EAAK6G,EAAF7G,EAAOA,IAAKksB,EAAS/Q,EAASsD,EAASze,GAAI+a,OAEjD0D,IAAUD,EAAcC,GAC5ByN,EAAS/Q,EAASsD,EAAU1D,GAIhC1b,KAAKkZ,MAAMyF,SAAS7C,IAAW,EAC/B9b,KAAKkZ,MAAMwF,IAAI5C,IAAW,QA4BtBkR,IAAI,SAAStsB,EAAQjB,EAAOD,GAClCC,EAAOD,SACHud,GAAM,0CACN0F,QAAW,0CACXwK,YAAe,0BACfC,aACIC,aACI/rB,KAAQ,QACR2R,SAAY,EACZJ,OAAWL,KAAQ,MAEvB8a,iBACIhsB,KAAQ,UACRyR,QAAW,GAEfwa,yBACI9a,QAAaD,KAAQ,kCAAqCgb,UAAW,KAEzEC,aACI7a,QAAU,QAAS,UAAW,UAAW,OAAQ,SAAU,SAAU,WAEzE8a,aACIpsB,KAAQ,QACRuR,OAAWvR,KAAQ,UACnB2R,SAAY,EACZW,aAAe,IAGvBtS,KAAQ,SACRoS,YACIuJ,IACI3b,KAAQ,SACRsJ,OAAU,OAEd+X,SACIrhB,KAAQ,SACRsJ,OAAU,OAEd+iB,OACIrsB,KAAQ,UAEZ6rB,aACI7rB,KAAQ,UAEZksB,aACAla,YACIhS,KAAQ,SACRyR,QAAW,EACX6a,kBAAoB,GAExB9a,SACIxR,KAAQ,UAEZusB,kBACIvsB,KAAQ,UACRksB,WAAW,GAEfza,SACIzR,KAAQ,UAEZssB,kBACItsB,KAAQ,UACRksB,WAAW,GAEfta,WAAeV,KAAQ,iCACvBW,WAAeX,KAAQ,yCACvBiB,SACInS,KAAQ,SACRsJ,OAAU,SAEdoc,iBACItU,QACMpR,KAAQ,YACRkR,KAAQ,MAEdgb,cAEJ3a,OACIH,QACMF,KAAQ,MACRA,KAAQ,8BAEdgb,cAEJxa,UAAcR,KAAQ,iCACtBS,UAAcT,KAAQ,yCACtBoB,aACItS,KAAQ,UACRksB,WAAW,GAEfpa,eAAmBZ,KAAQ,iCAC3Ba,eAAmBb,KAAQ,yCAC3BmB,UAAcnB,KAAQ,6BACtBwV,sBACItV,QACMpR,KAAQ,YACRkR,KAAQ,MAEdgb,cAEJJ,aACI9rB,KAAQ,SACR0mB,sBAA0BxV,KAAQ,KAClCgb,cAEJ9Z,YACIpS,KAAQ,SACR0mB,sBAA0BxV,KAAQ,KAClCgb,cAEJ3F,mBACIvmB,KAAQ,SACR0mB,sBAA0BxV,KAAQ,KAClCgb,cAEJ7a,cACIrR,KAAQ,SACR0mB,sBACItV,QACMF,KAAQ,MACRA,KAAQ,gCAItBI,QACItR,KAAQ,QACR2R,SAAY,EACZW,aAAe,GAEnBtS,MACIoR,QACMF,KAAQ,8BAENlR,KAAQ,QACRuR,OAAWL,KAAQ,6BACnBS,SAAY,EACZW,aAAe,KAI3BnB,OAAWD,KAAQ,6BACnBE,OAAWF,KAAQ,6BACnBgB,OAAWhB,KAAQ,6BACnBe,KAASf,KAAQ,MAErBG,cACIkb,kBAAsB,WACtBD,kBAAsB,YAE1BJ,mBAGEM,IAAI,SAASltB,EAAQjB,EAAOD,GAClCC,EAAOD,SACHud,GAAM,yFACN0F,QAAW,0CACXwK,YAAe,yCACfC,aACIC,aACI/rB,KAAQ,QACR2R,SAAY,EACZJ,OAAWL,KAAQ,MAEvB8a,iBACIhsB,KAAQ,UACRyR,QAAW,GAEfwa,yBACI9a,QAAaD,KAAQ,kCAAqCgb,UAAW,KAEzEC,aACI7a,QAAU,QAAS,UAAW,UAAW,OAAQ,SAAU,SAAU,WAEzE8a,aACIpsB,KAAQ,QACRuR,OAAWvR,KAAQ,UACnB2R,SAAY,EACZW,aAAe,GAEnBiO,OACIvgB,KAAQ,SACRqS,UAAc,SACdD,YACImO,OACIvgB,KAAQ,SACRsJ,OAAU,0BAGlBod,sBAAwB,IAGhC1mB,KAAQ,SACRoS,YACIuJ,IACI3b,KAAQ,SACRsJ,OAAU,OAEd+X,SACIrhB,KAAQ,SACRsJ,OAAU,OAEd+iB,OACIrsB,KAAQ,UAEZ6rB,aACI7rB,KAAQ,UAEZksB,aACAla,YACIZ,QAEQpR,KAAQ,SACRyR,QAAW,EACX6a,kBAAoB,IAEtBpb,KAAQ,yBAGlBM,SACIJ,QACMpR,KAAQ,WACRkR,KAAQ,yBAGlBqb,kBACInb,QAEQpR,KAAQ,UACRksB,WAAW,IAEbhb,KAAQ,yBAGlBO,SACIL,QACMpR,KAAQ,WACRkR,KAAQ,yBAGlBob,kBACIlb,QAEQpR,KAAQ,UACRksB,WAAW,IAEbhb,KAAQ,yBAGlBU,WACIR,QACMF,KAAQ,kCACRA,KAAQ,yBAGlBW,WACIT,QACMF,KAAQ,0CACRA,KAAQ,yBAGlBiB,SACIf,QAEQpR,KAAQ,SACRsJ,OAAU,UAEZ4H,KAAQ,yBAGlBwU,iBACItU,QACMpR,KAAQ,YACRkR,KAAQ,MACRA,KAAQ,wBAEdgb,cAEJ3a,OACIH,QACMF,KAAQ,MACRA,KAAQ,8BAEdgb,cAEJxa,UACIN,QACMF,KAAQ,kCACRA,KAAQ,yBAGlBS,UACIP,QACMF,KAAQ,0CACRA,KAAQ,yBAGlBoB,aACIlB,QAEQpR,KAAQ,UACRksB,WAAW,IAEbhb,KAAQ,yBAGlBY,eACIV,QACMF,KAAQ,kCACRA,KAAQ,yBAGlBa,eACIX,QACMF,KAAQ,0CACRA,KAAQ,yBAGlBmB,UACIjB,QACMF,KAAQ,8BACRA,KAAQ,yBAGlBwV,sBACItV,QACMpR,KAAQ,YACRkR,KAAQ,MACRA,KAAQ,wBAEdgb,cAEJJ,aACI9rB,KAAQ,SACR0mB,sBAA0BxV,KAAQ,KAClCgb,cAEJ9Z,YACIpS,KAAQ,SACR0mB,sBAA0BxV,KAAQ,KAClCgb,cAEJ3F,mBACIvmB,KAAQ,SACR0mB,sBAA0BxV,KAAQ,KAClCgb,cAEJ7a,cACIrR,KAAQ,SACR0mB,sBACItV,QACMF,KAAQ,MACRA,KAAQ,gCAItBI,QACIF,QAEQpR,KAAQ,QACR2R,SAAY,EACZW,aAAe,IAEjBpB,KAAQ,yBAGlBlR,MACIoR,QACMF,KAAQ,8BAENlR,KAAQ,QACRuR,OAAWL,KAAQ,6BACnBS,SAAY,EACZW,aAAe,KAI3BnB,OAAWD,KAAQ,6BACnBE,OAAWF,KAAQ,6BACnBgB,OAAWhB,KAAQ,6BACnBe,KAASf,KAAQ,KACjB5H,QACI8H,QACMpR,KAAQ,WACRkR,KAAQ,yBAGlBub,eACIrb,QACMpR,KAAQ,WACRkR,KAAQ,yBAGlBwb,eACItb,QACMpR,KAAQ,WACRkR,KAAQ,yBAGlByb,wBACIvb,QAEQpR,KAAQ,UACRksB,WAAW,IAEbhb,KAAQ,yBAGlB0b,wBACIxb,QAEQpR,KAAQ,UACRksB,WAAW,IAEbhb,KAAQ,yBAGlB2b,UACIzb,WAEMF,KAAQ,yBAGlB4b,UAAc5b,KAAQ,KACtBmW,eACIrnB,KAAQ,SACR0mB,sBACI1mB,KAAQ,SACRqS,UAAc,UACdD,YACIZ,SACIJ,QACMF,KAAQ,kCACRA,KAAQ,yBAGlBO,SACIL,QACMF,KAAQ,0CACRA,KAAQ,yBAGlB/B,QAAY+B,KAAQ,MAExBwV,sBAAwB,GAE5BwF,cAEJa,UACI/sB,KAAQ,QACRuR,OACIc,UAAc,QACdD,YACI4a,MAAQ9b,KAAQ,KAChB6Y,MACI3Y,QACMpR,KAAQ,YACRkR,KAAQ,OAGlB+b,YAAcjtB,KAAQ,YAE1B0mB,sBAAwB,EACxBrV,cACI4b,YAAc,UAK9B5b,cACIkb,kBAAsB,WACtBD,kBAAsB,WACtBG,eAAmB,UACnBC,eAAmB,UACnBC,wBAA4B,iBAC5BC,wBAA4B,kBAEhCV,mBAGEgB,IAAI,SAAS5tB,EAAQjB,EAAOD,GAClC,YAUA,SAAS+uB,GAASC,GAChB,GAAIA,EAAIjd,KAAKkd,QAAS,EAAO,CAC3B,GAAIC,GAAahuB,EAAQ,6BACzB8tB,GAAIG,cAAcD,EAAYE,GAEhCJ,EAAIK,WAAW,YAAclT,OAAQjb,EAAQ,oBAAqB6rB,YAAY,EAAMjrB,OAAQ,SAC5FktB,EAAIK,WAAW,YAAcztB,KAAM,QAASwa,MAAOkT,GAEnD,IAAIC,GAAcruB,EAAQ,uBAC1B8tB,GAAIK,WAAW,iBAAmBztB,KAAM,SAAUua,OAAQoT,EAAaxC,YAAY,EAAMjrB,OAAQ,SACjGktB,EAAIK,WAAW,iBAAmBztB,KAAM,SAAUua,OAAQoT,EAAaxC,YAAY,EAAMjrB,OAAQ,SACjGktB,EAAIK,WAAW,0BACfL,EAAIK,WAAW,0BAEfL,EAAIK,WAAW,iBACfL,EAAIK,WAAW,UAAYlT,OAAQjb,EAAQ,kBAAmB6rB,YAAY,EAAMjrB,OAAQ,SAG1F,QAASwtB,GAAcve,GACrB,OACE8C,KAASV,OAAWU,IAAO9C,KA5B/B,GAAIqe,GAAiB,uFAErBnvB,GAAOD,SACLwvB,OAAQT,EACRK,eAAgBA,KA4BfK,uBAAuB,GAAGC,mBAAmB,GAAGC,iBAAiB,GAAGC,6BAA6B,KAAKC,IAAI,SAAS3uB,EAAQjB,EAAOD,GACrI,GAAI8vB,GAAuB,mBAATC,MAAuBA,KAAO7uB,EAAQ,UAExDjB,GAAOD,QAAU,SAAUsH,EAAKyK,GACvBA,IAAMA,MACS,kBAATA,KAAqBA,GAASie,IAAKje,GAC9C,IAAIke,GAAQle,EAAKke,OAAS,EACL,iBAAVA,KAAoBA,EAAQvnB,MAAMunB,EAAM,GAAGttB,KAAK,KAC3D,IAAIutB,GAAiC,iBAAhBne,GAAKme,OAAwBne,EAAKme,QAAS,EAC5DC,EAAWpe,EAAKoe,UAAY,SAASxpB,EAAK9D,GAAS,MAAOA,IAE1DmtB,EAAMje,EAAKie,KAAO,SAAWjwB,GAC7B,MAAO,UAAUqwB,GACb,MAAO,UAAUnvB,EAAGuU,GAChB,GAAI6a,IAAS1pB,IAAK1F,EAAG4B,MAAOutB,EAAKnvB,IAC7BqvB,GAAS3pB,IAAK6O,EAAG3S,MAAOutB,EAAK5a,GACjC,OAAOzV,GAAEswB,EAAMC,MAGxBve,EAAKie,KAEJO,IACJ,OAAO,SAAU9mB,GAAW+mB,EAAQ7pB,EAAKypB,EAAMtN,GAC3C,GAAI2N,GAASR,EAAS,KAAO,GAAIvnB,OAAMoa,EAAQ,GAAGngB,KAAKstB,GAAU,GAC7DS,EAAiBT,EAAQ,KAAO,GAQpC,IANIG,GAAQA,EAAKO,QAAiC,kBAAhBP,GAAKO,SACnCP,EAAOA,EAAKO,UAGhBP,EAAOD,EAAS5uB,KAAKivB,EAAQ7pB,EAAKypB,GAErBlnB,SAATknB,EAAJ,CAGA,GAAoB,gBAATA,IAA8B,OAATA,EAC5B,MAAON,GAAKrmB,UAAU2mB,EAE1B,IAAI3nB,EAAQ2nB,GAAO,CAEf,IAAK,GADD7rB,MACKpD,EAAI,EAAOivB,EAAK5uB,OAATL,EAAiBA,IAAK,CAClC,GAAI+c,GAAOzU,EAAU2mB,EAAMjvB,EAAGivB,EAAKjvB,GAAI2hB,EAAM,IAAMgN,EAAKrmB,UAAU,KAClElF,GAAIrB,KAAKutB,EAASR,EAAQ/R,GAE9B,MAAO,IAAM3Z,EAAI5B,KAAK,KAAO8tB,EAAS,IAGtC,GAA2B,KAAvBF,EAAKjoB,QAAQ8nB,GAAc,CAC3B,GAAIF,EAAQ,MAAOJ,GAAKrmB,UAAU,YAClC,MAAM,IAAI4D,WAAU,yCAEnBkjB,EAAKrtB,KAAKktB,EAIf,KAAK,GAFD9mB,GAAOH,EAAWinB,GAAMQ,KAAKZ,GAAOA,EAAII,IACxC7rB,KACKpD,EAAI,EAAOmI,EAAK9H,OAATL,EAAiBA,IAAK,CAClC,GAAIwF,GAAM2C,EAAKnI,GACX0B,EAAQ4G,EAAU2mB,EAAMzpB,EAAKypB,EAAKzpB,GAAMmc,EAAM,EAElD,IAAIjgB,EAAJ,CAEA,GAAIguB,GAAWf,EAAKrmB,UAAU9C,GACxB+pB,EACA7tB,CAEN0B,GAAIrB,KAAKutB,EAASR,EAAQY,IAE9B,MAAO,IAAMtsB,EAAI5B,KAAK,KAAO8tB,EAAS,OAEzCK,GAAIxpB,GAAO,GAAIA,EAAK,GAG7B,IAAImB,GAAUC,MAAMD,SAAW,SAAUL,GACrC,MAA+B,sBAArBQ,SAASrH,KAAK6G,IAGxBe,EAAa3B,OAAO8B,MAAQ,SAAUhC,GACtC,GAAIypB,GAAMvpB,OAAOC,UAAUL,gBAAkB,WAAc,OAAO,GAC9DkC,IACJ,KAAK,GAAI3C,KAAOW,GACRypB,EAAIxvB,KAAK+F,EAAKX,IAAM2C,EAAKpG,KAAKyD,EAEtC,OAAO2C,MAGR0nB,QAAU,KAAKC,IAAI,SAAS/vB,EAAQjB,EAAOD,GAC9CA,EAAQwJ,MAAQtI,EAAQ,eACxBlB,EAAQyJ,UAAYvI,EAAQ,qBAEzBgwB,cAAc,GAAGC,kBAAkB,KAAKC,IAAI,SAASlwB,EAAQjB,EAAOD,GACvE,GAAIqxB,GACAC,EAWAC,EA4IA1uB,EAtJA2uB,GACIC,IAAM,IACNC,KAAM,KACNC,IAAM,IACNnc,EAAM,KACNzV,EAAM,KACNa,EAAM,KACNC,EAAM,KACNF,EAAM,KAIVgB,EAAQ,SAAU+D,GAEd,MACIuD,KAAS,cACT2oB,QAASlsB,EACT2rB,GAASA,EACTE,KAASA,IAIjBM,EAAO,SAAUC,GAWb,MATIA,IAAKA,IAAMR,GACX3vB,EAAM,aAAemwB,EAAI,iBAAmBR,EAAK,KAMrDA,EAAKC,EAAKpiB,OAAOkiB,GACjBA,GAAM,EACCC,GAGXhR,EAAS,WAEL,GAAIA,GACAle,EAAS,EAMb,KAJW,MAAPkvB,IACAlvB,EAAS,IACTyvB,EAAK,MAEFP,GAAM,KAAa,KAANA,GAChBlvB,GAAUkvB,EACVO,GAEJ,IAAW,MAAPP,EAEA,IADAlvB,GAAU,IACHyvB,KAAUP,GAAM,KAAa,KAANA,GAC1BlvB,GAAUkvB,CAGlB,IAAW,MAAPA,GAAqB,MAAPA,EAOd,IANAlvB,GAAUkvB,EACVO,KACW,MAAPP,GAAqB,MAAPA,KACdlvB,GAAUkvB,EACVO,KAEGP,GAAM,KAAa,KAANA,GAChBlvB,GAAUkvB,EACVO,GAIR,OADAvR,IAAUle,EACL4G,SAASsX,GAGHA,MAFP3e,GAAM,eAMdS,EAAS,WAEL,GAAI2vB,GACA5wB,EAEA6wB,EADA5vB,EAAS,EAIb,IAAW,MAAPkvB,EACA,KAAOO,KAAQ,CACX,GAAW,MAAPP,EAEA,MADAO,KACOzvB,CACJ,IAAW,OAAPkvB,EAEP,GADAO,IACW,MAAPP,EAAY,CAEZ,IADAU,EAAQ,EACH7wB,EAAI,EAAO,EAAJA,IACR4wB,EAAME,SAASJ,IAAQ,IAClB7oB,SAAS+oB,IAFC5wB,GAAK,EAKpB6wB,EAAgB,GAARA,EAAaD,CAEzB3vB,IAAU4E,OAAOC,aAAa+qB,OAC3B,CAAA,GAA2B,gBAAhBR,GAAQF,GAGtB,KAFAlvB,IAAUovB,EAAQF,OAKtBlvB,IAAUkvB,EAItB3vB,EAAM,eAGVuwB,EAAQ,WAIJ,KAAOZ,GAAY,KAANA,GACTO,KAIRM,EAAO,WAIH,OAAQb,GACR,IAAK,IAKD,MAJAO,GAAK,KACLA,EAAK,KACLA,EAAK,KACLA,EAAK,MACE,CACX,KAAK,IAMD,MALAA,GAAK,KACLA,EAAK,KACLA,EAAK,KACLA,EAAK,KACLA,EAAK,MACE,CACX,KAAK,IAKD,MAJAA,GAAK;AACLA,EAAK,KACLA,EAAK,KACLA,EAAK,KACE,KAEXlwB,EAAM,eAAiB2vB,EAAK,MAKhCtvB,EAAQ,WAIJ,GAAIA,KAEJ,IAAW,MAAPsvB,EAAY,CAGZ,GAFAO,EAAK,KACLK,IACW,MAAPZ,EAEA,MADAO,GAAK,KACE7vB,CAEX,MAAOsvB,GAAI,CAGP,GAFAtvB,EAAMkB,KAAKL,KACXqvB,IACW,MAAPZ,EAEA,MADAO,GAAK,KACE7vB,CAEX6vB,GAAK,KACLK,KAGRvwB,EAAM,cAGV0e,EAAS,WAIL,GAAI1Z,GACA0Z,IAEJ,IAAW,MAAPiR,EAAY,CAGZ,GAFAO,EAAK,KACLK,IACW,MAAPZ,EAEA,MADAO,GAAK,KACExR,CAEX,MAAOiR,GAAI,CASP,GARA3qB,EAAMvE,IACN8vB,IACAL,EAAK,KACDrqB,OAAOJ,eAAe7F,KAAK8e,EAAQ1Z,IACnChF,EAAM,kBAAoBgF,EAAM,KAEpC0Z,EAAO1Z,GAAO9D,IACdqvB,IACW,MAAPZ,EAEA,MADAO,GAAK,KACExR,CAEXwR,GAAK,KACLK,KAGRvwB,EAAM,cAGdkB,GAAQ,WAMJ,OADAqvB,IACQZ,GACR,IAAK,IACD,MAAOjR,IACX,KAAK,IACD,MAAOre,IACX,KAAK,IACD,MAAOI,IACX,KAAK,IACD,MAAOke,IACX,SACI,MAAOgR,IAAM,KAAa,KAANA,EAAYhR,IAAW6R,MAOnDlyB,EAAOD,QAAU,SAAUoL,EAAQgnB,GAC/B,GAAIlwB,EAiBJ,OAfAqvB,GAAOnmB,EACPimB,EAAK,EACLC,EAAK,IACLpvB,EAASW,IACTqvB,IACIZ,GACA3vB,EAAM,gBASgB,kBAAZywB,GAA0B,QAASC,GAAKC,EAAQ3rB,GAC1D,GAAI5C,GAAGoE,EAAGtF,EAAQyvB,EAAO3rB,EACzB,IAAI9D,GAA0B,gBAAVA,GAChB,IAAKkB,IAAKlB,GACF2E,OAAOC,UAAUL,eAAe7F,KAAKsB,EAAOkB,KAC5CoE,EAAIkqB,EAAKxvB,EAAOkB,GACNmF,SAANf,EACAtF,EAAMkB,GAAKoE,QAEJtF,GAAMkB,GAK7B,OAAOquB,GAAQ7wB,KAAK+wB,EAAQ3rB,EAAK9D,KAClCiuB,GAAI5uB,GAAS,IAAOA,QAGrBqwB,IAAI,SAASrxB,EAAQjB,EAAOD,GAgBlC,QAASwyB,GAAMpwB,GAOX,MADAqwB,GAAUC,UAAY,EACfD,EAAUxsB,KAAK7D,GAAU,IAAMA,EAAOG,QAAQkwB,EAAW,SAAUxxB,GACtE,GAAI6wB,GAAI7C,EAAKhuB,EACb,OAAoB,gBAAN6wB,GAAiBA,EAC3B,OAAS,OAAS7wB,EAAEgC,WAAW,GAAG2F,SAAS,KAAK1C,MAAM,MACzD,IAAM,IAAM9D,EAAS,IAG9B,QAAS+T,GAAIxP,EAAK2rB,GAEd,GAAInxB,GACA4C,EACAoE,EACA3G,EAEAmxB,EADAC,EAAOC,EAEPhwB,EAAQyvB,EAAO3rB,EAenB,QAZI9D,GAA0B,gBAAVA,IACY,kBAAjBA,GAAM8tB,SACjB9tB,EAAQA,EAAM8tB,OAAOhqB,IAKN,kBAARmsB,KACPjwB,EAAQiwB,EAAIvxB,KAAK+wB,EAAQ3rB,EAAK9D,UAInBA,IACX,IAAK,SACD,MAAO2vB,GAAM3vB,EAEjB,KAAK,SAED,MAAOmG,UAASnG,GAASmE,OAAOnE,GAAS,MAE7C,KAAK,UACL,IAAK,OAID,MAAOmE,QAAOnE,EAElB,KAAK,SACD,IAAKA,EAAO,MAAO,MAKnB,IAJAgwB,GAAOpC,EACPkC,KAG+C,mBAA3CnrB,OAAOC,UAAUmB,SAASmqB,MAAMlwB,GAA6B,CAE7D,IADArB,EAASqB,EAAMrB,OACVL,EAAI,EAAOK,EAAJL,EAAYA,GAAK,EACzBwxB,EAAQxxB,GAAKgV,EAAIhV,EAAG0B,IAAU,MASlC,OAJAsF,GAAuB,IAAnBwqB,EAAQnxB,OAAe,KAAOqxB,EAC9B,MAAQA,EAAMF,EAAQhwB,KAAK,MAAQkwB,GAAO,KAAOD,EAAO,IACxD,IAAMD,EAAQhwB,KAAK,KAAO,IAC9BkwB,EAAMD,EACCzqB,EAKX,GAAI2qB,GAAsB,gBAARA,GAEd,IADAtxB,EAASsxB,EAAItxB,OACRL,EAAI,EAAOK,EAAJL,EAAYA,GAAK,EACzB4C,EAAI+uB,EAAI3xB,GACS,gBAAN4C,KACPoE,EAAIgO,EAAIpS,EAAGlB,GACPsF,GACAwqB,EAAQzvB,KAAKsvB,EAAMzuB,IAAM8uB,EAAM,KAAO,KAAO1qB,QAOzD,KAAKpE,IAAKlB,GACF2E,OAAOC,UAAUL,eAAe7F,KAAKsB,EAAOkB,KAC5CoE,EAAIgO,EAAIpS,EAAGlB,GACPsF,GACAwqB,EAAQzvB,KAAKsvB,EAAMzuB,IAAM8uB,EAAM,KAAO,KAAO1qB,GAajE,OAJAA,GAAuB,IAAnBwqB,EAAQnxB,OAAe,KAAOqxB,EAC9B,MAAQA,EAAMF,EAAQhwB,KAAK,MAAQkwB,GAAO,KAAOD,EAAO,IACxD,IAAMD,EAAQhwB,KAAK,KAAO,IAC9BkwB,EAAMD,EACCzqB,GAzHf,GAEI0qB,GACApC,EAUAqC,EAZAL,EAAY,2HAGZxD,GACI+D,KAAM,MACNC,IAAM,MACNC,KAAM,MACNC,KAAM,MACNC,KAAM,MACN3B,IAAM,MACNC,KAAM,OAkHdzxB,GAAOD,QAAU,SAAU6C,EAAOstB,EAAUF,GACxC,GAAI9uB,EAMJ,IALA0xB,EAAM,GACNpC,EAAS,GAIY,gBAAVR,GACP,IAAK9uB,EAAI,EAAO8uB,EAAJ9uB,EAAWA,GAAK,EACxBsvB,GAAU,QAIQ,gBAAVR,KACZQ,EAASR,EAMb,IADA6C,EAAM3C,EACFA,GAAgC,kBAAbA,KACC,gBAAbA,IAAoD,gBAApBA,GAAS3uB,QAChD,KAAM,IAAIJ,OAAM,iBAKpB,OAAO+U,GAAI,IAAK2a,GAAIjuB,UAGlBmsB,KAAO,SAAS9tB,EAAQjB,EAAOD,GACrC,YAkBA,SAASqzB,GAAuBld,GAC9B,MAAOmd,GAAkBrtB,KAAKkQ,GAShC,QAAS1V,KAAIsR,GA6CX,QAASG,GAASqhB,EAAc1T,GAC9B,GAAI1X,EACJ,IAA2B,gBAAhBorB,IAET,GADAprB,EAAIqrB,EAAUD,IACTprB,EAAG,KAAM,IAAI/G,OAAM,8BAAgCmyB,EAAe,SAClE,CACL,GAAIlhB,GAAYC,EAAWihB,EAC3BprB,GAAIkK,EAAUH,UAAYgL,EAAS7K,GAGrC,GAAIohB,GAAQtrB,EAAE0X,EAEd,OADAtf,GAAKuB,OAASqG,EAAErG,OACT2xB,EAST,QAASrhB,GAAQrB,GACf,GAAIsB,GAAYC,EAAWvB,EAC3B,OAAOsB,GAAUH,UAAYgL,EAAS7K,GASxC,QAASX,GAAUX,EAAQpK,EAAK+sB,EAAiBC,GAC/C,GAAIjrB,MAAMD,QAAQsI,GAChB,IAAK,GAAI5P,GAAE,EAAK4P,EAAOvP,OAATL,EAAiBA,IAAKuQ,EAAUX,EAAO5P,QADvD,CAKAwF,EAAM2E,EAAQkS,YAAY7W,GAAOoK,EAAOwM,IACxCqW,EAAYjtB,EACZ,IAAI0L,GAAY9R,EAAKkR,SAAS9K,GAAO2L,EAAWvB,EAAQ2iB,GAAiB,EACzErhB,GAAU4c,KAAO0E,GAUnB,QAASxE,GAAcpe,EAAQpK,EAAK+sB,GAClChiB,EAAUX,EAAQpK,EAAK+sB,GAAiB,GAU1C,QAASrX,GAAetL,EAAQ8iB,GAC9B,GAAI5Q,GAAUlS,EAAOkS,UAAY1iB,EAAKwR,KAAK0R,GAAKA,EAAG2L,eAAiBA,GAChE0E,EAAmBvzB,EAAKic,SAASpF,GACrC7W,GAAKic,SAASpF,IAAiC,kBAApB0c,GACLT,EACAC,CACtB,IAAIG,GAAQvhB,EAAS+Q,EAASlS,EAE9B,IADAxQ,EAAKic,SAASpF,IAAM0c,GACfL,GAASI,EAAiB,CAC7B,GAAIjC,GAAU,qBAAuBmC,GACrC,IAAgC,OAA5BxzB,EAAKwR,KAAKsK,eACT,KAAM,IAAIjb,OAAMwwB,EADkBlX,SAAQ/Y,MAAMiwB,GAGvD,MAAO6B,GAST,QAASD,GAAUQ,GACjB,GAAI3hB,GAAY4hB,EAAcD,EAC9B,cAAe3hB,IACb,IAAK,SAAU,MAAOA,GAAUH,UAAYgL,EAAS7K,EACrD,KAAK,SAAU,MAAOmhB,GAAUnhB,IAKpC,QAAS4hB,GAAcD,GAErB,MADAA,GAAS1oB,EAAQkS,YAAYwW,GACtBzzB,EAAKkR,SAASuiB,IAAWzzB,EAAKgR,MAAMyiB,GAS7C,QAASE,GAAaX,GACpB,aAAeA,IACb,IAAK,SACH,GAAIlhB,GAAY4hB,EAAcV,EAC9BhzB,GAAKkS,OAAOG,IAAIP,EAAU8hB,eACnB5zB,GAAKkR,SAAS8hB,SACdhzB,GAAKgR,MAAMgiB,EAClB,MACF,KAAK,SACH,GAAIY,GAAUtY,EAAgB0X,EAC9BhzB,GAAKkS,OAAOG,IAAIuhB,EAChB,IAAI5W,GAAKgW,EAAahW,EAClBA,KACFA,EAAKjS,EAAQkS,YAAYD,SAClBhd,GAAKgR,MAAMgM,KAM1B,QAASjL,GAAWvB,EAAQqjB,EAAgBC,GAC1C,GAAqB,gBAAVtjB,GAAoB,KAAM,IAAI3P,OAAM,0BAC/C,IAAI+yB,GAAUtY,EAAgB9K,GAC1BujB,EAAS/zB,EAAKkS,OAAOE,IAAIwhB,EAC7B,IAAIG,EAAQ,MAAOA,EAEnBD,GAAkBA,GAAmB9zB,EAAKwR,KAAKwiB,iBAAkB,CAEjE,IAAIhX,GAAKjS,EAAQkS,YAAYzM,EAAOwM,GAChCA,IAAM8W,GAAiBT,EAAYrW,GAEnChd,EAAKwR,KAAKsK,kBAAmB,GAAU+X,GACzC/X,EAAetL,GAAQ,EAEzB,IAAI+H,GAAYxN,EAAQsT,IAAIrd,KAAKhB,EAAMwQ,GAEnCsB,EAAY,GAAI4K,IAClBM,GAAIA,EACJxM,OAAQA,EACR+H,UAAWA,EACXqb,QAASA,GAMX,OAHa,KAAT5W,EAAG,IAAa8W,IAAiB9zB,EAAKgR,MAAMgM,GAAMlL,GACtD9R,EAAKkS,OAAOC,IAAIyhB,EAAS9hB,GAElBA,EAIT,QAAS6K,GAAS7K,EAAW3Q,GA+B3B,QAAS8yB,KACP,GAAIrsB,GAAIkK,EAAUH,SACdhQ,EAASiG,EAAE4qB,MAAM,KAAM0B,UAE3B,OADAD,GAAa1yB,OAASqG,EAAErG,OACjBI,EAlCT,GAAImQ,EAAUqiB,UAKZ,MAJAriB,GAAUH,SAAWsiB,EACrBA,EAAazjB,OAASsB,EAAUtB,OAChCyjB,EAAa1yB,OAAS,KACtB0yB,EAAa9yB,KAAOA,EAAOA,EAAO8yB,EAC3BA,CAETniB,GAAUqiB,WAAY,CAEtB,IAAIC,GAAYp0B,EAAKwR,KAAK4W,iBACtBiM,EAAYr0B,EAAKwR,KAAK8X,WACtBxX,GAAU4c,OACR0F,IAAWp0B,EAAKwR,KAAK4W,kBAAmB,GACxCiM,IAAWr0B,EAAKwR,KAAK8X,aAAc,GAEzC,IAAI1hB,EACJ,KAAMA,EAAI0sB,EAActzB,KAAKhB,EAAM8R,EAAUtB,OAAQrP,EAAM2Q,EAAUyG,WACrE,QACEzG,EAAUqiB,WAAY,EAClBC,IAAWp0B,EAAKwR,KAAK4W,iBAAmBgM,GACxCC,IAAWr0B,EAAKwR,KAAK8X,YAAc+K,GAOzC,MAJAviB,GAAUH,SAAW/J,EACrBkK,EAAUwI,KAAO1S,EAAE0S,KACnBxI,EAAU2H,OAAS7R,EAAE6R,OACrB3H,EAAU3Q,KAAOyG,EAAEzG,KACZyG,EAkBT,QAAS4rB,GAAWjyB,EAAQiQ,GAE1B,GADAjQ,EAASA,GAAUvB,EAAKuB,QACnBA,EAAQ,MAAO,WACpBiQ,GAAOA,KAKP,KAAK,GAJD+iB,GAAY/iB,EAAK+iB,WAAa,KAC9BhU,EAAU/O,EAAK+O,SAAW,OAE1ByQ,EAAO,GACFpwB,EAAE,EAAKW,EAAON,OAATL,EAAiBA,IAAK,CAClC,GAAIT,GAAIoB,EAAOX,EACXT,KAAG6wB,GAAQzQ,EAAUpgB,EAAEq0B,SAAW,IAAMr0B,EAAEkxB,QAAUkD,GAE1D,MAAOvD,GAAKrrB,MAAM,GAAI4uB,EAAUtzB,QASlC,QAASwzB,GAAU/rB,EAAMiC,GACF,gBAAVA,KAAoBA,EAAS,GAAIsM,QAAOtM,IACnD3K,EAAKic,SAASvT,GAAQiC,EAIxB,QAAS+pB,KACP,GAAI10B,EAAKwR,KAAKkd,QAAS,EAAO,CAC5B,GAAIC,GAAahuB,EAAQ,mCACzBiuB,GAAcD,EAAYE,GAAgB,GAC1C7uB,EAAKgR,MAAM,iCAAmC6d,EAGhD,GAAI8F,GAAc30B,EAAKwR,KAAKojB,OAC5B,IAAKD,EACL,GAAIxsB,MAAMD,QAAQysB,GAAcxjB,EAAUwjB,OACrC,KAAK,GAAIvuB,KAAOuuB,GAAaxjB,EAAUwjB,EAAYvuB,GAAMA,GAIhE,QAASyuB,KACP,IAAK,GAAInsB,KAAQ1I,GAAKwR,KAAK6D,QAAS,CAClC,GAAI1K,GAAS3K,EAAKwR,KAAK6D,QAAQ3M,EAC/B+rB,GAAU/rB,EAAMiC,IAKpB,QAAS0oB,GAAYrW,GACnB,GAAIhd,EAAKkR,SAAS8L,IAAOhd,EAAKgR,MAAMgM,GAClC,KAAM,IAAInc,OAAM,0BAA4Bmc,EAAK,oBAvSrD,KAAM/c,eAAgBC,MAAM,MAAO,IAAIA,KAAIsR,EAC3C,IAAIxR,GAAOC,IAEXA,MAAKuR,KAAOA,MACZvR,KAAKiR,YACLjR,KAAK+Q,SACL/Q,KAAKgc,SAAW5G,EAAQpV,KAAKuR,KAAK7G,QAClC1K,KAAKiS,OAASjS,KAAKuR,KAAKsjB,OAAS,GAAI7iB,GACrChS,KAAKsR,mBACLtR,KAAKkZ,MAAQuF,IAIbze,KAAK0R,SAAWA,EAChB1R,KAAK4R,QAAUA,EACf5R,KAAKkR,UAAYA,EACjBlR,KAAK2uB,cAAgBA,EACrB3uB,KAAK6b,eAAiBA,EACtB7b,KAAKgzB,UAAYA,EACjBhzB,KAAK0zB,aAAeA,EACpB1zB,KAAKw0B,UAAYA,EACjBx0B,KAAKuzB,WAAaA,EAElBvzB,KAAK8R,WAAaA,EAClB9R,KAAK0c,SAAWA,EAEhB+X,IACIz0B,KAAKuR,KAAK6D,SAASwf,IAEQ,YAA3B50B,KAAKuR,KAAKujB,gBACZ90B,KAAKuR,KAAK8U,wBAAyB,GAEjCrmB,KAAKuR,KAAK0R,IAAIA,EAAG+L,OAAOhvB,MAE5BA,KAAKuR,KAAK+W,aAAetoB,KAAKuR,KAAK+W,cAAgB1K,EAAAA,EA7DrD,GAAIyW,GAAgB3zB,EAAQ,aACxBoK,EAAUpK,EAAQ,qBAClBsR,EAAQtR,EAAQ,WAChB+b,EAAe/b,EAAQ,wBACvB2a,EAAkB3a,EAAQ,yBAC1B0U,EAAU1U,EAAQ,qBAClB+d,EAAQ/d,EAAQ,mBAChBuiB,EAAKviB,EAAQ,OAEjBjB,GAAOD,QAAUS,IAEjBA,IAAIgH,UAAU8tB,aAAer0B,EAAQ,WACrCT,IAAIgH,UAAU4nB,WAAanuB,EAAQ,YAEnC,IAAIkuB,GAAiB,yCACjBkE,EAAoB,8CAuTrBkC,UAAU,EAAEC,UAAU,EAAEC,YAAY,GAAGC,oBAAoB,GAAGC,oBAAoB,GAAGC,kBAAkB,GAAGC,uBAAuB,GAAGC,YAAY,GAAGC,mCAAmC,GAAGC,OAAO,GAAGlZ,wBAAwB,aAAa","file":"ajv.min.js"}
\ No newline at end of file
diff --git a/htdocs/Libs/Codemirror/codemirror.css b/htdocs/Libs/Codemirror/codemirror.css
new file mode 100644
index 0000000..49ec873
--- /dev/null
+++ b/htdocs/Libs/Codemirror/codemirror.css
@@ -0,0 +1,352 @@
+/* BASICS */
+
+.CodeMirror {
+  /* Set height, width, borders, and global font properties here */
+  font-family: monospace;
+  height: 300px;
+  color: black;
+}
+
+/* PADDING */
+
+.CodeMirror-lines {
+  padding: 4px 0; /* Vertical padding around content */
+}
+.CodeMirror pre {
+  padding: 0 4px; /* Horizontal padding of content */
+}
+
+.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+  background-color: white; /* The little square between H and V scrollbars */
+}
+
+/* GUTTER */
+
+.CodeMirror-gutters {
+  border-right: 1px solid #ddd;
+  background-color: #f7f7f7;
+  white-space: nowrap;
+}
+.CodeMirror-linenumbers {}
+.CodeMirror-linenumber {
+  padding: 0 3px 0 5px;
+  min-width: 20px;
+  text-align: right;
+  color: #999;
+  white-space: nowrap;
+}
+
+.CodeMirror-guttermarker { color: black; }
+.CodeMirror-guttermarker-subtle { color: #999; }
+
+/* CURSOR */
+
+.CodeMirror-cursor {
+  border-left: 1px solid black;
+  border-right: none;
+  width: 0;
+}
+/* Shown when moving in bi-directional text */
+.CodeMirror div.CodeMirror-secondarycursor {
+  border-left: 1px solid silver;
+}
+.cm-fat-cursor .CodeMirror-cursor {
+  width: auto;
+  border: 0;
+  background: #7e7;
+}
+.cm-fat-cursor div.CodeMirror-cursors {
+  z-index: 1;
+}
+
+.cm-animate-fat-cursor {
+  width: auto;
+  border: 0;
+  -webkit-animation: blink 1.06s steps(1) infinite;
+  -moz-animation: blink 1.06s steps(1) infinite;
+  animation: blink 1.06s steps(1) infinite;
+  background-color: #7e7;
+}
+@-moz-keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+@-webkit-keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+@keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+
+/* Can style cursor different in overwrite (non-insert) mode */
+.CodeMirror-overwrite .CodeMirror-cursor {}
+
+.cm-tab { display: inline-block; text-decoration: inherit; }
+
+.CodeMirror-ruler {
+  border-left: 1px solid #ccc;
+  position: absolute;
+}
+
+/* DEFAULT THEME */
+
+.cm-s-default .cm-header {color: blue;}
+.cm-s-default .cm-quote {color: #090;}
+.cm-negative {color: #d44;}
+.cm-positive {color: #292;}
+.cm-header, .cm-strong {font-weight: bold;}
+.cm-em {font-style: italic;}
+.cm-link {text-decoration: underline;}
+.cm-strikethrough {text-decoration: line-through;}
+
+.cm-s-default .cm-keyword {color: #708;}
+.cm-s-default .cm-atom {color: #219;}
+.cm-s-default .cm-number {color: #164;}
+.cm-s-default .cm-def {color: #00f;}
+.cm-s-default .cm-variable,
+.cm-s-default .cm-punctuation,
+.cm-s-default .cm-property,
+.cm-s-default .cm-operator {}
+.cm-s-default .cm-variable-2 {color: #05a;}
+.cm-s-default .cm-variable-3 {color: #085;}
+.cm-s-default .cm-comment {color: #a50;}
+.cm-s-default .cm-string {color: #a11;}
+.cm-s-default .cm-string-2 {color: #f50;}
+.cm-s-default .cm-meta {color: #555;}
+.cm-s-default .cm-qualifier {color: #555;}
+.cm-s-default .cm-builtin {color: #30a;}
+.cm-s-default .cm-bracket {color: #997;}
+.cm-s-default .cm-tag {color: #170;}
+.cm-s-default .cm-attribute {color: #00c;}
+.cm-s-default .cm-hr {color: #999;}
+.cm-s-default .cm-link {color: #00c;}
+
+.cm-s-default .cm-error {color: #f00;}
+.cm-invalidchar {color: #f00;}
+
+.CodeMirror-composing { border-bottom: 2px solid; }
+
+/* Default styles for common addons */
+
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
+.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
+.CodeMirror-activeline-background {background: #e8f2ff;}
+
+/* STOP */
+
+/* The rest of this file contains styles related to the mechanics of
+   the editor. You probably shouldn't touch them. */
+
+.CodeMirror {
+  position: relative;
+  overflow: hidden;
+  background: white;
+}
+
+.CodeMirror-scroll {
+  overflow: scroll !important; /* Things will break if this is overridden */
+  /* 30px is the magic margin used to hide the element's real scrollbars */
+  /* See overflow: hidden in .CodeMirror */
+  margin-bottom: -30px; margin-right: -30px;
+  padding-bottom: 30px;
+  height: 100%;
+  outline: none; /* Prevent dragging from highlighting the element */
+  position: relative;
+}
+.CodeMirror-sizer {
+  position: relative;
+  border-right: 30px solid transparent;
+}
+
+/* The fake, visible scrollbars. Used to force redraw during scrolling
+   before actuall scrolling happens, thus preventing shaking and
+   flickering artifacts. */
+.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+  position: absolute;
+  z-index: 6;
+  display: none;
+}
+.CodeMirror-vscrollbar {
+  right: 0; top: 0;
+  overflow-x: hidden;
+  overflow-y: scroll;
+}
+.CodeMirror-hscrollbar {
+  bottom: 0; left: 0;
+  overflow-y: hidden;
+  overflow-x: scroll;
+}
+.CodeMirror-scrollbar-filler {
+  right: 0; bottom: 0;
+}
+.CodeMirror-gutter-filler {
+  left: 0; bottom: 0;
+}
+
+.CodeMirror-gutters {
+  position: absolute; left: 0; top: 0;
+  z-index: 3;
+}
+.CodeMirror-gutter {
+  white-space: normal;
+  height: 100%;
+  display: inline-block;
+  margin-bottom: -30px;
+  /* Hack to make IE7 behave */
+  *zoom:1;
+  *display:inline;
+}
+.CodeMirror-gutter-wrapper {
+  position: absolute;
+  z-index: 4;
+  background: none !important;
+  border: none !important;
+}
+.CodeMirror-gutter-background {
+  position: absolute;
+  top: 0; bottom: 0;
+  z-index: 4;
+}
+.CodeMirror-gutter-elt {
+  position: absolute;
+  cursor: default;
+  z-index: 4;
+}
+.CodeMirror-gutter-wrapper {
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  user-select: none;
+}
+
+.CodeMirror-lines {
+  cursor: text;
+  min-height: 1px; /* prevents collapsing before first draw */
+}
+.CodeMirror pre {
+  /* Reset some styles that the rest of the page might have set */
+  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
+  border-width: 0;
+  background: transparent;
+  font-family: inherit;
+  font-size: inherit;
+  margin: 0;
+  white-space: pre;
+  word-wrap: normal;
+  line-height: inherit;
+  color: inherit;
+  z-index: 2;
+  position: relative;
+  overflow: visible;
+  -webkit-tap-highlight-color: transparent;
+}
+.CodeMirror-wrap pre {
+  word-wrap: break-word;
+  white-space: pre-wrap;
+  word-break: normal;
+}
+
+.CodeMirror-linebackground {
+  position: absolute;
+  left: 0; right: 0; top: 0; bottom: 0;
+  z-index: 0;
+}
+
+.CodeMirror-linewidget {
+  position: relative;
+  z-index: 2;
+  overflow: auto;
+}
+
+.CodeMirror-widget {}
+
+.CodeMirror-code {
+  outline: none;
+}
+
+/* Force content-box sizing for the elements where we expect it */
+.CodeMirror-scroll,
+.CodeMirror-sizer,
+.CodeMirror-gutter,
+.CodeMirror-gutters,
+.CodeMirror-linenumber {
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+
+.CodeMirror-measure {
+  position: absolute;
+  width: 100%;
+  height: 0;
+  overflow: hidden;
+  visibility: hidden;
+}
+
+.CodeMirror-cursor { position: absolute; }
+.CodeMirror-measure pre { position: static; }
+
+div.CodeMirror-cursors {
+  visibility: hidden;
+  position: relative;
+  z-index: 3;
+}
+div.CodeMirror-dragcursors {
+  visibility: visible;
+}
+
+.CodeMirror-focused div.CodeMirror-cursors {
+  visibility: visible;
+}
+
+.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
+.CodeMirror-crosshair { cursor: crosshair; }
+.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
+.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
+
+.cm-searching {
+  background: #ffa;
+  background: rgba(255, 255, 0, .4);
+}
+
+/* IE7 hack to prevent it from returning funny offsetTops on the spans */
+.CodeMirror span { *vertical-align: text-bottom; }
+
+/* Used to force a border model for a node */
+.cm-force-border { padding-right: .1px; }
+
+@media print {
+  /* Hide the cursor when printing */
+  .CodeMirror div.CodeMirror-cursors {
+    visibility: hidden;
+  }
+}
+
+/* See issue #2901 */
+.cm-tab-wrap-hack:after { content: ''; }
+
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext { background: none; }
+
+.CodeMirror-foldmarker {    
+  font-family: arial;
+}
+.CodeMirror-foldgutter {
+  width: .7em;
+}
+.CodeMirror-foldgutter-open,
+.CodeMirror-foldgutter-folded {
+  color: #555;
+  cursor: pointer;
+}
+.CodeMirror-foldgutter-open:after {
+  content: "\25BE";
+}
+.CodeMirror-foldgutter-folded:after {
+  content: "\25B8";
+}
diff --git a/htdocs/Libs/Codemirror/codemirror.custom.js b/htdocs/Libs/Codemirror/codemirror.custom.js
new file mode 100644
index 0000000..59ec31c
--- /dev/null
+++ b/htdocs/Libs/Codemirror/codemirror.custom.js
@@ -0,0 +1,9544 @@
+/* CodeMirror - Minified & Bundled
+   Generated on 2015. 08. 31. with http://codemirror.net/doc/compress.html
+   Version: HEAD
+
+   CodeMirror Library:
+   - codemirror.js
+   Modes:
+   - css.js
+   - htmlmixed.js
+   - javascript.js
+   - perl.js
+   - python.js
+   - shell.js
+   - xml.js
+   Add-ons:
+   - active-line.js
+   - brace-fold.js
+   - closebrackets.js
+   - closetag.js
+   - foldcode.js
+   - foldgutter.js
+   - indent-fold.js
+   - match-highlighter.js
+   - matchbrackets.js
+   - matchtags.js
+   - search.js
+   - xml-fold.js
+ */
+ 
+! function (a) {
+    if ("object" == typeof exports && "object" == typeof module) module.exports = a();
+    else {
+        if ("function" == typeof define && define.amd) return define([], a);
+        this.CodeMirror = a()
+    }
+}(function () {
+    "use strict";
+
+    function v(a, b) {
+        if (!(this instanceof v)) return new v(a, b);
+        this.options = b = b ? hg(b) : {}, hg(Ad, b, !1), I(b);
+        var c = b.value;
+        "string" == typeof c && (c = new af(c, b.mode, null, b.lineSeparator)), this.doc = c;
+        var g = new v.inputStyles[b.inputStyle](this),
+            h = this.display = new w(a, c, g);
+        h.wrapper.CodeMirror = this, E(this), C(this), b.lineWrapping && (this.display.wrapper.className += " CodeMirror-wrap"), b.autofocus && !n && h.input.focus(), M(this), this.state = {
+            keyMaps: [],
+            overlays: [],
+            modeGen: 0,
+            overwrite: !1,
+            delayingBlurEvent: !1,
+            focused: !1,
+            suppressEdits: !1,
+            pasteIncoming: !1,
+            cutIncoming: !1,
+            selectingText: !1,
+            draggingText: !1,
+            highlight: new Yf,
+            keySeq: null,
+            specialChars: null
+        };
+        var i = this;
+        d && 11 > e && setTimeout(function () {
+            i.display.input.reset(!0)
+        }, 20), pc(this), Bg(), Vb(this), this.curOp.forceUpdate = !0, ef(this, c), b.autofocus && !n || i.hasFocus() ? setTimeout(ig(Zc, this), 20) : $c(this);
+        for (var j in Bd) Bd.hasOwnProperty(j) && Bd[j](this, b[j], Dd);
+        R(this), b.finishInit && b.finishInit(this);
+        for (var k = 0; k < Hd.length; ++k) Hd[k](this);
+        Xb(this), f && b.lineWrapping && "optimizelegibility" == getComputedStyle(h.lineDiv)
+            .textRendering && (h.lineDiv.style.textRendering = "auto")
+    }
+
+    function w(b, c, g) {
+        var h = this;
+        this.input = g, h.scrollbarFiller = pg("div", null, "CodeMirror-scrollbar-filler"), h.scrollbarFiller.setAttribute("cm-not-content", "true"), h.gutterFiller = pg("div", null, "CodeMirror-gutter-filler"), h.gutterFiller.setAttribute("cm-not-content", "true"), h.lineDiv = pg("div", null, "CodeMirror-code"), h.selectionDiv = pg("div", null, null, "position: relative; z-index: 1"), h.cursorDiv = pg("div", null, "CodeMirror-cursors"), h.measure = pg("div", null, "CodeMirror-measure"), h.lineMeasure = pg("div", null, "CodeMirror-measure"), h.lineSpace = pg("div", [h.measure, h.lineMeasure, h.selectionDiv, h.cursorDiv, h.lineDiv], null, "position: relative; outline: none"), h.mover = pg("div", [pg("div", [h.lineSpace], "CodeMirror-lines")], null, "position: relative"), h.sizer = pg("div", [h.mover], "CodeMirror-sizer"), h.sizerWidth = null, h.heightForcer = pg("div", null, null, "position: absolute; height: " + Tf + "px; width: 1px;"), h.gutters = pg("div", null, "CodeMirror-gutters"), h.lineGutter = null, h.scroller = pg("div", [h.sizer, h.heightForcer, h.gutters], "CodeMirror-scroll"), h.scroller.setAttribute("tabIndex", "-1"), h.wrapper = pg("div", [h.scrollbarFiller, h.gutterFiller, h.scroller], "CodeMirror"), d && 8 > e && (h.gutters.style.zIndex = -1, h.scroller.style.paddingRight = 0), f || a && n || (h.scroller.draggable = !0), b && (b.appendChild ? b.appendChild(h.wrapper) : b(h.wrapper)), h.viewFrom = h.viewTo = c.first, h.reportedViewFrom = h.reportedViewTo = c.first, h.view = [], h.renderedView = null, h.externalMeasured = null, h.viewOffset = 0, h.lastWrapHeight = h.lastWrapWidth = 0, h.updateLineNumbers = null, h.nativeBarWidth = h.barHeight = h.barWidth = 0, h.scrollbarsClipped = !1, h.lineNumWidth = h.lineNumInnerWidth = h.lineNumChars = null, h.alignWidgets = !1, h.cachedCharWidth = h.cachedTextHeight = h.cachedPaddingH = null, h.maxLine = null, h.maxLineLength = 0, h.maxLineChanged = !1, h.wheelDX = h.wheelDY = h.wheelStartX = h.wheelStartY = null, h.shift = !1, h.selForContextMenu = null, h.activeTouch = null, g.init(h)
+    }
+
+    function x(a) {
+        a.doc.mode = v.getMode(a.options, a.doc.modeOption), y(a)
+    }
+
+    function y(a) {
+        a.doc.iter(function (a) {
+            a.stateAfter && (a.stateAfter = null), a.styles && (a.styles = null)
+        }), a.doc.frontier = a.doc.first, ib(a, 100), a.state.modeGen++, a.curOp && ic(a)
+    }
+
+    function z(a) {
+        a.options.lineWrapping ? (xg(a.display.wrapper, "CodeMirror-wrap"), a.display.sizer.style.minWidth = "", a.display.sizerWidth = null) : (wg(a.display.wrapper, "CodeMirror-wrap"), H(a)), B(a), ic(a), Fb(a), setTimeout(function () {
+            N(a)
+        }, 100)
+    }
+
+    function A(a) {
+        var b = Rb(a.display),
+            c = a.options.lineWrapping,
+            d = c && Math.max(5, a.display.scroller.clientWidth / Sb(a.display) - 3);
+        return function (e) {
+            if (we(a.doc, e)) return 0;
+            var f = 0;
+            if (e.widgets)
+                for (var g = 0; g < e.widgets.length; g++) e.widgets[g].height && (f += e.widgets[g].height);
+            return c ? f + (Math.ceil(e.text.length / d) || 1) * b : f + b
+        }
+    }
+
+    function B(a) {
+        var b = a.doc,
+            c = A(a);
+        b.iter(function (a) {
+            var b = c(a);
+            b != a.height && jf(a, b)
+        })
+    }
+
+    function C(a) {
+        a.display.wrapper.className = a.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + a.options.theme.replace(/(^|\s)\s*/g, " cm-s-"), Fb(a)
+    }
+
+    function D(a) {
+        E(a), ic(a), setTimeout(function () {
+            Q(a)
+        }, 20)
+    }
+
+    function E(a) {
+        var b = a.display.gutters,
+            c = a.options.gutters;
+        rg(b);
+        for (var d = 0; d < c.length; ++d) {
+            var e = c[d],
+                f = b.appendChild(pg("div", null, "CodeMirror-gutter " + e));
+            "CodeMirror-linenumbers" == e && (a.display.lineGutter = f, f.style.width = (a.display.lineNumWidth || 1) + "px")
+        }
+        b.style.display = d ? "" : "none", F(a)
+    }
+
+    function F(a) {
+        var b = a.display.gutters.offsetWidth;
+        a.display.sizer.style.marginLeft = b + "px"
+    }
+
+    function G(a) {
+        if (0 == a.height) return 0;
+        for (var c, b = a.text.length, d = a; c = pe(d);) {
+            var e = c.find(0, !0);
+            d = e.from.line, b += e.from.ch - e.to.ch
+        }
+        for (d = a; c = qe(d);) {
+            var e = c.find(0, !0);
+            b -= d.text.length - e.from.ch, d = e.to.line, b += d.text.length - e.to.ch
+        }
+        return b
+    }
+
+    function H(a) {
+        var b = a.display,
+            c = a.doc;
+        b.maxLine = ff(c, c.first), b.maxLineLength = G(b.maxLine), b.maxLineChanged = !0, c.iter(function (a) {
+            var c = G(a);
+            c > b.maxLineLength && (b.maxLineLength = c, b.maxLine = a)
+        })
+    }
+
+    function I(a) {
+        var b = dg(a.gutters, "CodeMirror-linenumbers"); - 1 == b && a.lineNumbers ? a.gutters = a.gutters.concat(["CodeMirror-linenumbers"]) : b > -1 && !a.lineNumbers && (a.gutters = a.gutters.slice(0), a.gutters.splice(b, 1))
+    }
+
+    function J(a) {
+        var b = a.display,
+            c = b.gutters.offsetWidth,
+            d = Math.round(a.doc.height + nb(a.display));
+        return {
+            clientHeight: b.scroller.clientHeight,
+            viewHeight: b.wrapper.clientHeight,
+            scrollWidth: b.scroller.scrollWidth,
+            clientWidth: b.scroller.clientWidth,
+            viewWidth: b.wrapper.clientWidth,
+            barLeft: a.options.fixedGutter ? c : 0,
+            docHeight: d,
+            scrollHeight: d + pb(a) + b.barHeight,
+            nativeBarWidth: b.nativeBarWidth,
+            gutterWidth: c
+        }
+    }
+
+    function K(a, b, c) {
+        this.cm = c;
+        var f = this.vert = pg("div", [pg("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"),
+            g = this.horiz = pg("div", [pg("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
+        a(f), a(g), Jf(f, "scroll", function () {
+            f.clientHeight && b(f.scrollTop, "vertical")
+        }), Jf(g, "scroll", function () {
+            g.clientWidth && b(g.scrollLeft, "horizontal")
+        }), this.checkedOverlay = !1, d && 8 > e && (this.horiz.style.minHeight = this.vert.style.minWidth = "18px")
+    }
+
+    function L() {}
+
+    function M(a) {
+        a.display.scrollbars && (a.display.scrollbars.clear(), a.display.scrollbars.addClass && wg(a.display.wrapper, a.display.scrollbars.addClass)), a.display.scrollbars = new v.scrollbarModel[a.options.scrollbarStyle](function (b) {
+            a.display.wrapper.insertBefore(b, a.display.scrollbarFiller), Jf(b, "mousedown", function () {
+                a.state.focused && setTimeout(function () {
+                    a.display.input.focus()
+                }, 0)
+            }), b.setAttribute("cm-not-content", "true")
+        }, function (b, c) {
+            "horizontal" == c ? Ic(a, b) : Hc(a, b)
+        }, a), a.display.scrollbars.addClass && xg(a.display.wrapper, a.display.scrollbars.addClass)
+    }
+
+    function N(a, b) {
+        b || (b = J(a));
+        var c = a.display.barWidth,
+            d = a.display.barHeight;
+        O(a, b);
+        for (var e = 0; 4 > e && c != a.display.barWidth || d != a.display.barHeight; e++) c != a.display.barWidth && a.options.lineWrapping && $(a), O(a, J(a)), c = a.display.barWidth, d = a.display.barHeight
+    }
+
+    function O(a, b) {
+        var c = a.display,
+            d = c.scrollbars.update(b);
+        c.sizer.style.paddingRight = (c.barWidth = d.right) + "px", c.sizer.style.paddingBottom = (c.barHeight = d.bottom) + "px", d.right && d.bottom ? (c.scrollbarFiller.style.display = "block", c.scrollbarFiller.style.height = d.bottom + "px", c.scrollbarFiller.style.width = d.right + "px") : c.scrollbarFiller.style.display = "", d.bottom && a.options.coverGutterNextToScrollbar && a.options.fixedGutter ? (c.gutterFiller.style.display = "block", c.gutterFiller.style.height = d.bottom + "px", c.gutterFiller.style.width = b.gutterWidth + "px") : c.gutterFiller.style.display = ""
+    }
+
+    function P(a, b, c) {
+        var d = c && null != c.top ? Math.max(0, c.top) : a.scroller.scrollTop;
+        d = Math.floor(d - mb(a));
+        var e = c && null != c.bottom ? c.bottom : d + a.wrapper.clientHeight,
+            f = lf(b, d),
+            g = lf(b, e);
+        if (c && c.ensure) {
+            var h = c.ensure.from.line,
+                i = c.ensure.to.line;
+            f > h ? (f = h, g = lf(b, mf(ff(b, h)) + a.wrapper.clientHeight)) : Math.min(i, b.lastLine()) >= g && (f = lf(b, mf(ff(b, i)) - a.wrapper.clientHeight), g = i)
+        }
+        return {
+            from: f,
+            to: Math.max(g, f + 1)
+        }
+    }
+
+    function Q(a) {
+        var b = a.display,
+            c = b.view;
+        if (b.alignWidgets || b.gutters.firstChild && a.options.fixedGutter) {
+            for (var d = T(b) - b.scroller.scrollLeft + a.doc.scrollLeft, e = b.gutters.offsetWidth, f = d + "px", g = 0; g < c.length; g++)
+                if (!c[g].hidden) {
+                    a.options.fixedGutter && c[g].gutter && (c[g].gutter.style.left = f);
+                    var h = c[g].alignable;
+                    if (h)
+                        for (var i = 0; i < h.length; i++) h[i].style.left = f
+                }
+            a.options.fixedGutter && (b.gutters.style.left = d + e + "px")
+        }
+    }
+
+    function R(a) {
+        if (!a.options.lineNumbers) return !1;
+        var b = a.doc,
+            c = S(a.options, b.first + b.size - 1),
+            d = a.display;
+        if (c.length != d.lineNumChars) {
+            var e = d.measure.appendChild(pg("div", [pg("div", c)], "CodeMirror-linenumber CodeMirror-gutter-elt")),
+                f = e.firstChild.offsetWidth,
+                g = e.offsetWidth - f;
+            return d.lineGutter.style.width = "", d.lineNumInnerWidth = Math.max(f, d.lineGutter.offsetWidth - g) + 1, d.lineNumWidth = d.lineNumInnerWidth + g, d.lineNumChars = d.lineNumInnerWidth ? c.length : -1, d.lineGutter.style.width = d.lineNumWidth + "px", F(a), !0
+        }
+        return !1
+    }
+
+    function S(a, b) {
+        return String(a.lineNumberFormatter(b + a.firstLineNumber))
+    }
+
+    function T(a) {
+        return a.scroller.getBoundingClientRect()
+            .left - a.sizer.getBoundingClientRect()
+            .left
+    }
+
+    function U(a, b, c) {
+        var d = a.display;
+        this.viewport = b, this.visible = P(d, a.doc, b), this.editorIsHidden = !d.wrapper.offsetWidth, this.wrapperHeight = d.wrapper.clientHeight, this.wrapperWidth = d.wrapper.clientWidth, this.oldDisplayWidth = qb(a), this.force = c, this.dims = aa(a), this.events = []
+    }
+
+    function V(a) {
+        var b = a.display;
+        !b.scrollbarsClipped && b.scroller.offsetWidth && (b.nativeBarWidth = b.scroller.offsetWidth - b.scroller.clientWidth, b.heightForcer.style.height = pb(a) + "px", b.sizer.style.marginBottom = -b.nativeBarWidth + "px", b.sizer.style.borderRightWidth = pb(a) + "px", b.scrollbarsClipped = !0)
+    }
+
+    function W(a, b) {
+        var c = a.display,
+            d = a.doc;
+        if (b.editorIsHidden) return kc(a), !1;
+        if (!b.force && b.visible.from >= c.viewFrom && b.visible.to <= c.viewTo && (null == c.updateLineNumbers || c.updateLineNumbers >= c.viewTo) && c.renderedView == c.view && 0 == oc(a)) return !1;
+        R(a) && (kc(a), b.dims = aa(a));
+        var e = d.first + d.size,
+            f = Math.max(b.visible.from - a.options.viewportMargin, d.first),
+            g = Math.min(e, b.visible.to + a.options.viewportMargin);
+        c.viewFrom < f && f - c.viewFrom < 20 && (f = Math.max(d.first, c.viewFrom)), c.viewTo > g && c.viewTo - g < 20 && (g = Math.min(e, c.viewTo)), u && (f = ue(a.doc, f), g = ve(a.doc, g));
+        var h = f != c.viewFrom || g != c.viewTo || c.lastWrapHeight != b.wrapperHeight || c.lastWrapWidth != b.wrapperWidth;
+        nc(a, f, g), c.viewOffset = mf(ff(a.doc, c.viewFrom)), a.display.mover.style.top = c.viewOffset + "px";
+        var i = oc(a);
+        if (!h && 0 == i && !b.force && c.renderedView == c.view && (null == c.updateLineNumbers || c.updateLineNumbers >= c.viewTo)) return !1;
+        var j = ug();
+        return i > 4 && (c.lineDiv.style.display = "none"), ba(a, c.updateLineNumbers, b.dims), i > 4 && (c.lineDiv.style.display = ""), c.renderedView = c.view, j && ug() != j && j.offsetHeight && j.focus(), rg(c.cursorDiv), rg(c.selectionDiv), c.gutters.style.height = c.sizer.style.minHeight = 0, h && (c.lastWrapHeight = b.wrapperHeight, c.lastWrapWidth = b.wrapperWidth, ib(a, 400)), c.updateLineNumbers = null, !0
+    }
+
+    function X(a, b) {
+        for (var c = b.viewport, d = !0;
+            (d && a.options.lineWrapping && b.oldDisplayWidth != qb(a) || (c && null != c.top && (c = {
+                top: Math.min(a.doc.height + nb(a.display) - rb(a), c.top)
+            }), b.visible = P(a.display, a.doc, c), !(b.visible.from >= a.display.viewFrom && b.visible.to <= a.display.viewTo))) && W(a, b); d = !1) {
+            $(a);
+            var e = J(a);
+            db(a), Z(a, e), N(a, e)
+        }
+        b.signal(a, "update", a), (a.display.viewFrom != a.display.reportedViewFrom || a.display.viewTo != a.display.reportedViewTo) && (b.signal(a, "viewportChange", a, a.display.viewFrom, a.display.viewTo), a.display.reportedViewFrom = a.display.viewFrom, a.display.reportedViewTo = a.display.viewTo)
+    }
+
+    function Y(a, b) {
+        var c = new U(a, b);
+        if (W(a, c)) {
+            $(a), X(a, c);
+            var d = J(a);
+            db(a), Z(a, d), N(a, d), c.finish()
+        }
+    }
+
+    function Z(a, b) {
+        a.display.sizer.style.minHeight = b.docHeight + "px";
+        var c = b.docHeight + a.display.barHeight;
+        a.display.heightForcer.style.top = c + "px", a.display.gutters.style.height = Math.max(c + pb(a), b.clientHeight) + "px"
+    }
+
+    function $(a) {
+        for (var b = a.display, c = b.lineDiv.offsetTop, f = 0; f < b.view.length; f++) {
+            var h, g = b.view[f];
+            if (!g.hidden) {
+                if (d && 8 > e) {
+                    var i = g.node.offsetTop + g.node.offsetHeight;
+                    h = i - c, c = i
+                } else {
+                    var j = g.node.getBoundingClientRect();
+                    h = j.bottom - j.top
+                }
+                var k = g.line.height - h;
+                if (2 > h && (h = Rb(b)), (k > .001 || -.001 > k) && (jf(g.line, h), _(g.line), g.rest))
+                    for (var l = 0; l < g.rest.length; l++) _(g.rest[l])
+            }
+        }
+    }
+
+    function _(a) {
+        if (a.widgets)
+            for (var b = 0; b < a.widgets.length; ++b) a.widgets[b].height = a.widgets[b].node.offsetHeight
+    }
+
+    function aa(a) {
+        for (var b = a.display, c = {}, d = {}, e = b.gutters.clientLeft, f = b.gutters.firstChild, g = 0; f; f = f.nextSibling, ++g) c[a.options.gutters[g]] = f.offsetLeft + f.clientLeft + e, d[a.options.gutters[g]] = f.clientWidth;
+        return {
+            fixedPos: T(b),
+            gutterTotalWidth: b.gutters.offsetWidth,
+            gutterLeft: c,
+            gutterWidth: d,
+            wrapperWidth: b.wrapper.clientWidth
+        }
+    }
+
+    function ba(a, b, c) {
+        function i(b) {
+            var c = b.nextSibling;
+            return f && o && a.display.currentWheelTarget == b ? b.style.display = "none" : b.parentNode.removeChild(b), c
+        }
+        for (var d = a.display, e = a.options.lineNumbers, g = d.lineDiv, h = g.firstChild, j = d.view, k = d.viewFrom, l = 0; l < j.length; l++) {
+            var m = j[l];
+            if (m.hidden);
+            else if (m.node && m.node.parentNode == g) {
+                for (; h != m.node;) h = i(h);
+                var p = e && null != b && k >= b && m.lineNumber;
+                m.changes && (dg(m.changes, "gutter") > -1 && (p = !1), ca(a, m, k, c)), p && (rg(m.lineNumber), m.lineNumber.appendChild(document.createTextNode(S(a.options, k)))), h = m.node.nextSibling
+            } else {
+                var n = ka(a, m, k, c);
+                g.insertBefore(n, h)
+            }
+            k += m.size
+        }
+        for (; h;) h = i(h)
+    }
+
+    function ca(a, b, c, d) {
+        for (var e = 0; e < b.changes.length; e++) {
+            var f = b.changes[e];
+            "text" == f ? ga(a, b) : "gutter" == f ? ia(a, b, c, d) : "class" == f ? ha(b) : "widget" == f && ja(a, b, d)
+        }
+        b.changes = null
+    }
+
+    function da(a) {
+        return a.node == a.text && (a.node = pg("div", null, null, "position: relative"), a.text.parentNode && a.text.parentNode.replaceChild(a.node, a.text), a.node.appendChild(a.text), d && 8 > e && (a.node.style.zIndex = 2)), a.node
+    }
+
+    function ea(a) {
+        var b = a.bgClass ? a.bgClass + " " + (a.line.bgClass || "") : a.line.bgClass;
+        if (b && (b += " CodeMirror-linebackground"), a.background) b ? a.background.className = b : (a.background.parentNode.removeChild(a.background), a.background = null);
+        else if (b) {
+            var c = da(a);
+            a.background = c.insertBefore(pg("div", null, b), c.firstChild)
+        }
+    }
+
+    function fa(a, b) {
+        var c = a.display.externalMeasured;
+        return c && c.line == b.line ? (a.display.externalMeasured = null, b.measure = c.measure, c.built) : Qe(a, b)
+    }
+
+    function ga(a, b) {
+        var c = b.text.className,
+            d = fa(a, b);
+        b.text == b.node && (b.node = d.pre), b.text.parentNode.replaceChild(d.pre, b.text), b.text = d.pre, d.bgClass != b.bgClass || d.textClass != b.textClass ? (b.bgClass = d.bgClass, b.textClass = d.textClass, ha(b)) : c && (b.text.className = c)
+    }
+
+    function ha(a) {
+        ea(a), a.line.wrapClass ? da(a)
+            .className = a.line.wrapClass : a.node != a.text && (a.node.className = "");
+        var b = a.textClass ? a.textClass + " " + (a.line.textClass || "") : a.line.textClass;
+        a.text.className = b || ""
+    }
+
+    function ia(a, b, c, d) {
+        if (b.gutter && (b.node.removeChild(b.gutter), b.gutter = null), b.gutterBackground && (b.node.removeChild(b.gutterBackground), b.gutterBackground = null), b.line.gutterClass) {
+            var e = da(b);
+            b.gutterBackground = pg("div", null, "CodeMirror-gutter-background " + b.line.gutterClass, "left: " + (a.options.fixedGutter ? d.fixedPos : -d.gutterTotalWidth) + "px; width: " + d.gutterTotalWidth + "px"), e.insertBefore(b.gutterBackground, b.text)
+        }
+        var f = b.line.gutterMarkers;
+        if (a.options.lineNumbers || f) {
+            var e = da(b),
+                g = b.gutter = pg("div", null, "CodeMirror-gutter-wrapper", "left: " + (a.options.fixedGutter ? d.fixedPos : -d.gutterTotalWidth) + "px");
+            if (a.display.input.setUneditable(g), e.insertBefore(g, b.text), b.line.gutterClass && (g.className += " " + b.line.gutterClass), !a.options.lineNumbers || f && f["CodeMirror-linenumbers"] || (b.lineNumber = g.appendChild(pg("div", S(a.options, c), "CodeMirror-linenumber CodeMirror-gutter-elt", "left: " + d.gutterLeft["CodeMirror-linenumbers"] + "px; width: " + a.display.lineNumInnerWidth + "px"))), f)
+                for (var h = 0; h < a.options.gutters.length; ++h) {
+                    var i = a.options.gutters[h],
+                        j = f.hasOwnProperty(i) && f[i];
+                    j && g.appendChild(pg("div", [j], "CodeMirror-gutter-elt", "left: " + d.gutterLeft[i] + "px; width: " + d.gutterWidth[i] + "px"))
+                }
+        }
+    }
+
+    function ja(a, b, c) {
+        b.alignable && (b.alignable = null);
+        for (var e, d = b.node.firstChild; d; d = e) {
+            var e = d.nextSibling;
+            "CodeMirror-linewidget" == d.className && b.node.removeChild(d)
+        }
+        la(a, b, c)
+    }
+
+    function ka(a, b, c, d) {
+        var e = fa(a, b);
+        return b.text = b.node = e.pre, e.bgClass && (b.bgClass = e.bgClass), e.textClass && (b.textClass = e.textClass), ha(b), ia(a, b, c, d), la(a, b, d), b.node
+    }
+
+    function la(a, b, c) {
+        if (ma(a, b.line, b, c, !0), b.rest)
+            for (var d = 0; d < b.rest.length; d++) ma(a, b.rest[d], b, c, !1)
+    }
+
+    function ma(a, b, c, d, e) {
+        if (b.widgets)
+            for (var f = da(c), g = 0, h = b.widgets; g < h.length; ++g) {
+                var i = h[g],
+                    j = pg("div", [i.node], "CodeMirror-linewidget");
+                i.handleMouseEvents || j.setAttribute("cm-ignore-events", "true"), na(i, j, c, d), a.display.input.setUneditable(j), e && i.above ? f.insertBefore(j, c.gutter || c.text) : f.appendChild(j), Nf(i, "redraw")
+            }
+    }
+
+    function na(a, b, c, d) {
+        if (a.noHScroll) {
+            (c.alignable || (c.alignable = []))
+            .push(b);
+            var e = d.wrapperWidth;
+            b.style.left = d.fixedPos + "px", a.coverGutter || (e -= d.gutterTotalWidth, b.style.paddingLeft = d.gutterTotalWidth + "px"), b.style.width = e + "px"
+        }
+        a.coverGutter && (b.style.zIndex = 5, b.style.position = "relative", a.noHScroll || (b.style.marginLeft = -d.gutterTotalWidth + "px"))
+    }
+
+    function qa(a) {
+        return oa(a.line, a.ch)
+    }
+
+    function ra(a, b) {
+        return pa(a, b) < 0 ? b : a
+    }
+
+    function sa(a, b) {
+        return pa(a, b) < 0 ? a : b
+    }
+
+    function ta(a) {
+        a.state.focused || (a.display.input.focus(), Zc(a))
+    }
+
+    function ua(a) {
+        return a.options.readOnly || a.doc.cantEdit
+    }
+
+    function wa(a, b, c, d, e) {
+        var f = a.doc;
+        a.display.shift = !1, d || (d = f.sel);
+        var g = a.state.pasteIncoming || "paste" == e,
+            h = f.splitLines(b),
+            i = null;
+        if (g && d.ranges.length > 1)
+            if (va && va.join("\n") == b) {
+                if (d.ranges.length % va.length == 0) {
+                    i = [];
+                    for (var j = 0; j < va.length; j++) i.push(f.splitLines(va[j]))
+                }
+            } else h.length == d.ranges.length && (i = eg(h, function (a) {
+                return [a]
+            }));
+        for (var j = d.ranges.length - 1; j >= 0; j--) {
+            var k = d.ranges[j],
+                l = k.from(),
+                m = k.to();
+            k.empty() && (c && c > 0 ? l = oa(l.line, l.ch - c) : a.state.overwrite && !g && (m = oa(m.line, Math.min(ff(f, m.line)
+                .text.length, m.ch + bg(h)
+                .length))));
+            var n = a.curOp.updateInput,
+                o = {
+                    from: l,
+                    to: m,
+                    text: i ? i[j % i.length] : h,
+                    origin: e || (g ? "paste" : a.state.cutIncoming ? "cut" : "+input")
+                };
+            hd(a.doc, o), Nf(a, "inputRead", a, o)
+        }
+        b && !g && ya(a, b), td(a), a.curOp.updateInput = n, a.curOp.typing = !0, a.state.pasteIncoming = a.state.cutIncoming = !1
+    }
+
+    function xa(a, b) {
+        var c = a.clipboardData && a.clipboardData.getData("text/plain");
+        return c ? (a.preventDefault(), ua(b) || b.options.disableInput || cc(b, function () {
+            wa(b, c, 0, null, "paste")
+        }), !0) : void 0
+    }
+
+    function ya(a, b) {
+        if (a.options.electricChars && a.options.smartIndent)
+            for (var c = a.doc.sel, d = c.ranges.length - 1; d >= 0; d--) {
+                var e = c.ranges[d];
+                if (!(e.head.ch > 100 || d && c.ranges[d - 1].head.line == e.head.line)) {
+                    var f = a.getModeAt(e.head),
+                        g = !1;
+                    if (f.electricChars) {
+                        for (var h = 0; h < f.electricChars.length; h++)
+                            if (b.indexOf(f.electricChars.charAt(h)) > -1) {
+                                g = vd(a, e.head.line, "smart");
+                                break
+                            }
+                    } else f.electricInput && f.electricInput.test(ff(a.doc, e.head.line)
+                        .text.slice(0, e.head.ch)) && (g = vd(a, e.head.line, "smart"));
+                    g && Nf(a, "electricInput", a, e.head.line)
+                }
+            }
+    }
+
+    function za(a) {
+        for (var b = [], c = [], d = 0; d < a.doc.sel.ranges.length; d++) {
+            var e = a.doc.sel.ranges[d].head.line,
+                f = {
+                    anchor: oa(e, 0),
+                    head: oa(e + 1, 0)
+                };
+            c.push(f), b.push(a.getRange(f.anchor, f.head))
+        }
+        return {
+            text: b,
+            ranges: c
+        }
+    }
+
+    function Aa(a) {
+        a.setAttribute("autocorrect", "off"), a.setAttribute("autocapitalize", "off"), a.setAttribute("spellcheck", "false")
+    }
+
+    function Ba(a) {
+        this.cm = a, this.prevInput = "", this.pollingFast = !1, this.polling = new Yf, this.inaccurateSelection = !1, this.hasSelection = !1, this.composing = null
+    }
+
+    function Ca() {
+        var a = pg("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none"),
+            b = pg("div", [a], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
+        return f ? a.style.width = "1000px" : a.setAttribute("wrap", "off"), m && (a.style.border = "1px solid black"), Aa(a), b
+    }
+
+    function Da(a) {
+        this.cm = a, this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null, this.polling = new Yf, this.gracePeriod = !1
+    }
+
+    function Ea(a, b) {
+        var c = wb(a, b.line);
+        if (!c || c.hidden) return null;
+        var d = ff(a.doc, b.line),
+            e = tb(c, d, b.line),
+            f = nf(d),
+            g = "left";
+        if (f) {
+            var h = Yg(f, b.ch);
+            g = h % 2 ? "right" : "left"
+        }
+        var i = Ab(e.map, b.ch, g);
+        return i.offset = "right" == i.collapse ? i.end : i.start, i
+    }
+
+    function Fa(a, b) {
+        return b && (a.bad = !0), a
+    }
+
+    function Ga(a, b, c) {
+        var d;
+        if (b == a.display.lineDiv) {
+            if (d = a.display.lineDiv.childNodes[c], !d) return Fa(a.clipPos(oa(a.display.viewTo - 1)), !0);
+            b = null, c = 0
+        } else
+            for (d = b;; d = d.parentNode) {
+                if (!d || d == a.display.lineDiv) return null;
+                if (d.parentNode && d.parentNode == a.display.lineDiv) break
+            }
+        for (var e = 0; e < a.display.view.length; e++) {
+            var f = a.display.view[e];
+            if (f.node == d) return Ha(f, b, c)
+        }
+    }
+
+    function Ha(a, b, c) {
+        function k(b, c, d) {
+            for (var e = -1; e < (j ? j.length : 0); e++)
+                for (var f = 0 > e ? i.map : j[e], g = 0; g < f.length; g += 3) {
+                    var h = f[g + 2];
+                    if (h == b || h == c) {
+                        var k = kf(0 > e ? a.line : a.rest[e]),
+                            l = f[g] + d;
+                        return (0 > d || h != b) && (l = f[g + (d ? 1 : 0)]), oa(k, l)
+                    }
+                }
+        }
+        var d = a.text.firstChild,
+            e = !1;
+        if (!b || !tg(d, b)) return Fa(oa(kf(a.line), 0), !0);
+        if (b == d && (e = !0, b = d.childNodes[c], c = 0, !b)) {
+            var f = a.rest ? bg(a.rest) : a.line;
+            return Fa(oa(kf(f), f.text.length), e)
+        }
+        var g = 3 == b.nodeType ? b : null,
+            h = b;
+        for (g || 1 != b.childNodes.length || 3 != b.firstChild.nodeType || (g = b.firstChild, c && (c = g.nodeValue.length)); h.parentNode != d;) h = h.parentNode;
+        var i = a.measure,
+            j = i.maps,
+            l = k(g, h, c);
+        if (l) return Fa(l, e);
+        for (var m = h.nextSibling, n = g ? g.nodeValue.length - c : 0; m; m = m.nextSibling) {
+            if (l = k(m, m.firstChild, 0)) return Fa(oa(l.line, l.ch - n), e);
+            n += m.textContent.length
+        }
+        for (var o = h.previousSibling, n = c; o; o = o.previousSibling) {
+            if (l = k(o, o.firstChild, -1)) return Fa(oa(l.line, l.ch + n), e);
+            n += m.textContent.length
+        }
+    }
+
+    function Ia(a, b, c, d, e) {
+        function i(a) {
+            return function (b) {
+                return b.id == a
+            }
+        }
+
+        function j(b) {
+            if (1 == b.nodeType) {
+                var c = b.getAttribute("cm-text");
+                if (null != c) return "" == c && (c = b.textContent.replace(/\u200b/g, "")), void(f += c);
+                var l, k = b.getAttribute("cm-marker");
+                if (k) {
+                    var m = a.findMarks(oa(d, 0), oa(e + 1, 0), i(+k));
+                    return void(m.length && (l = m[0].find()) && (f += gf(a.doc, l.from, l.to)
+                        .join(h)))
+                }
+                if ("false" == b.getAttribute("contenteditable")) return;
+                for (var n = 0; n < b.childNodes.length; n++) j(b.childNodes[n]);
+                /^(pre|div|p)$/i.test(b.nodeName) && (g = !0)
+            } else if (3 == b.nodeType) {
+                var o = b.nodeValue;
+                if (!o) return;
+                g && (f += h, g = !1), f += o
+            }
+        }
+        for (var f = "", g = !1, h = a.doc.lineSeparator(); j(b), b != c;) b = b.nextSibling;
+        return f
+    }
+
+    function Ja(a, b) {
+        this.ranges = a, this.primIndex = b
+    }
+
+    function Ka(a, b) {
+        this.anchor = a, this.head = b
+    }
+
+    function La(a, b) {
+        var c = a[b];
+        a.sort(function (a, b) {
+            return pa(a.from(), b.from())
+        }), b = dg(a, c);
+        for (var d = 1; d < a.length; d++) {
+            var e = a[d],
+                f = a[d - 1];
+            if (pa(f.to(), e.from()) >= 0) {
+                var g = sa(f.from(), e.from()),
+                    h = ra(f.to(), e.to()),
+                    i = f.empty() ? e.from() == e.head : f.from() == f.head;
+                b >= d && --b, a.splice(--d, 2, new Ka(i ? h : g, i ? g : h))
+            }
+        }
+        return new Ja(a, b)
+    }
+
+    function Ma(a, b) {
+        return new Ja([new Ka(a, b || a)], 0)
+    }
+
+    function Na(a, b) {
+        return Math.max(a.first, Math.min(b, a.first + a.size - 1))
+    }
+
+    function Oa(a, b) {
+        if (b.line < a.first) return oa(a.first, 0);
+        var c = a.first + a.size - 1;
+        return b.line > c ? oa(c, ff(a, c)
+            .text.length) : Pa(b, ff(a, b.line)
+            .text.length)
+    }
+
+    function Pa(a, b) {
+        var c = a.ch;
+        return null == c || c > b ? oa(a.line, b) : 0 > c ? oa(a.line, 0) : a
+    }
+
+    function Qa(a, b) {
+        return b >= a.first && b < a.first + a.size
+    }
+
+    function Ra(a, b) {
+        for (var c = [], d = 0; d < b.length; d++) c[d] = Oa(a, b[d]);
+        return c
+    }
+
+    function Sa(a, b, c, d) {
+        if (a.cm && a.cm.display.shift || a.extend) {
+            var e = b.anchor;
+            if (d) {
+                var f = pa(c, e) < 0;
+                f != pa(d, e) < 0 ? (e = c, c = d) : f != pa(c, d) < 0 && (c = d)
+            }
+            return new Ka(e, c)
+        }
+        return new Ka(d || c, c)
+    }
+
+    function Ta(a, b, c, d) {
+        Za(a, new Ja([Sa(a, a.sel.primary(), b, c)], 0), d)
+    }
+
+    function Ua(a, b, c) {
+        for (var d = [], e = 0; e < a.sel.ranges.length; e++) d[e] = Sa(a, a.sel.ranges[e], b[e], null);
+        var f = La(d, a.sel.primIndex);
+        Za(a, f, c)
+    }
+
+    function Va(a, b, c, d) {
+        var e = a.sel.ranges.slice(0);
+        e[b] = c, Za(a, La(e, a.sel.primIndex), d)
+    }
+
+    function Wa(a, b, c, d) {
+        Za(a, Ma(b, c), d)
+    }
+
+    function Xa(a, b) {
+        var c = {
+            ranges: b.ranges,
+            update: function (b) {
+                this.ranges = [];
+                for (var c = 0; c < b.length; c++) this.ranges[c] = new Ka(Oa(a, b[c].anchor), Oa(a, b[c].head))
+            }
+        };
+        return Lf(a, "beforeSelectionChange", a, c), a.cm && Lf(a.cm, "beforeSelectionChange", a.cm, c), c.ranges != b.ranges ? La(c.ranges, c.ranges.length - 1) : b
+    }
+
+    function Ya(a, b, c) {
+        var d = a.history.done,
+            e = bg(d);
+        e && e.ranges ? (d[d.length - 1] = b, $a(a, b, c)) : Za(a, b, c)
+    }
+
+    function Za(a, b, c) {
+        $a(a, b, c), uf(a, a.sel, a.cm ? a.cm.curOp.id : NaN, c)
+    }
+
+    function $a(a, b, c) {
+        (Rf(a, "beforeSelectionChange") || a.cm && Rf(a.cm, "beforeSelectionChange")) && (b = Xa(a, b));
+        var d = c && c.bias || (pa(b.primary()
+            .head, a.sel.primary()
+            .head) < 0 ? -1 : 1);
+        _a(a, bb(a, b, d, !0)), c && c.scroll === !1 || !a.cm || td(a.cm)
+    }
+
+    function _a(a, b) {
+        b.equals(a.sel) || (a.sel = b, a.cm && (a.cm.curOp.updateInput = a.cm.curOp.selectionChanged = !0, Qf(a.cm)), Nf(a, "cursorActivity", a))
+    }
+
+    function ab(a) {
+        _a(a, bb(a, a.sel, null, !1), Vf)
+    }
+
+    function bb(a, b, c, d) {
+        for (var e, f = 0; f < b.ranges.length; f++) {
+            var g = b.ranges[f],
+                h = cb(a, g.anchor, c, d),
+                i = cb(a, g.head, c, d);
+            (e || h != g.anchor || i != g.head) && (e || (e = b.ranges.slice(0, f)), e[f] = new Ka(h, i))
+        }
+        return e ? La(e, b.primIndex) : b
+    }
+
+    function cb(a, b, c, d) {
+        var e = !1,
+            f = b,
+            g = c || 1;
+        a.cantEdit = !1;
+        a: for (;;) {
+            var h = ff(a, f.line);
+            if (h.markedSpans)
+                for (var i = 0; i < h.markedSpans.length; ++i) {
+                    var j = h.markedSpans[i],
+                        k = j.marker;
+                    if ((null == j.from || (k.inclusiveLeft ? j.from <= f.ch : j.from < f.ch)) && (null == j.to || (k.inclusiveRight ? j.to >= f.ch : j.to > f.ch))) {
+                        if (d && (Lf(k, "beforeCursorEnter"), k.explicitlyCleared)) {
+                            if (h.markedSpans) {
+                                --i;
+                                continue
+                            }
+                            break
+                        }
+                        if (!k.atomic) continue;
+                        var l = k.find(0 > g ? -1 : 1);
+                        if (0 == pa(l, f) && (l.ch += g, l.ch < 0 ? l = l.line > a.first ? Oa(a, oa(l.line - 1)) : null : l.ch > h.text.length && (l = l.line < a.first + a.size - 1 ? oa(l.line + 1, 0) : null), !l)) {
+                            if (e) return d ? (a.cantEdit = !0, oa(a.first, 0)) : cb(a, b, c, !0);
+                            e = !0, l = b, g = -g
+                        }
+                        f = l;
+                        continue a
+                    }
+                }
+            return f
+        }
+    }
+
+    function db(a) {
+        a.display.input.showSelection(a.display.input.prepareSelection())
+    }
+
+    function eb(a, b) {
+        for (var c = a.doc, d = {}, e = d.cursors = document.createDocumentFragment(), f = d.selection = document.createDocumentFragment(), g = 0; g < c.sel.ranges.length; g++)
+            if (b !== !1 || g != c.sel.primIndex) {
+                var h = c.sel.ranges[g],
+                    i = h.empty();
+                (i || a.options.showCursorWhenSelecting) && fb(a, h.head, e), i || gb(a, h, f)
+            }
+        return d
+    }
+
+    function fb(a, b, c) {
+        var d = Lb(a, b, "div", null, null, !a.options.singleCursorHeightPerLine),
+            e = c.appendChild(pg("div", "\xa0", "CodeMirror-cursor"));
+        if (e.style.left = d.left + "px", e.style.top = d.top + "px", e.style.height = Math.max(0, d.bottom - d.top) * a.options.cursorHeight + "px", d.other) {
+            var f = c.appendChild(pg("div", "\xa0", "CodeMirror-cursor CodeMirror-secondarycursor"));
+            f.style.display = "", f.style.left = d.other.left + "px", f.style.top = d.other.top + "px", f.style.height = .85 * (d.other.bottom - d.other.top) + "px"
+        }
+    }
+
+    function gb(a, b, c) {
+        function j(a, b, c, d) {
+            0 > b && (b = 0), b = Math.round(b), d = Math.round(d), f.appendChild(pg("div", null, "CodeMirror-selected", "position: absolute; left: " + a + "px; top: " + b + "px; width: " + (null == c ? i - a : c) + "px; height: " + (d - b) + "px"))
+        }
+
+        function k(b, c, d) {
+            function m(c, d) {
+                return Kb(a, oa(b, c), "div", f, d)
+            }
+            var k, l, f = ff(e, b),
+                g = f.text.length;
+            return Og(nf(f), c || 0, null == d ? g : d, function (a, b, e) {
+                var n, o, p, f = m(a, "left");
+                if (a == b) n = f, o = p = f.left;
+                else {
+                    if (n = m(b - 1, "right"), "rtl" == e) {
+                        var q = f;
+                        f = n, n = q
+                    }
+                    o = f.left, p = n.right
+                }
+                null == c && 0 == a && (o = h), n.top - f.top > 3 && (j(o, f.top, null, f.bottom), o = h, f.bottom < n.top && j(o, f.bottom, null, n.top)), null == d && b == g && (p = i), (!k || f.top < k.top || f.top == k.top && f.left < k.left) && (k = f), (!l || n.bottom > l.bottom || n.bottom == l.bottom && n.right > l.right) && (l = n), h + 1 > o && (o = h), j(o, n.top, p - o, n.bottom)
+            }), {
+                start: k,
+                end: l
+            }
+        }
+        var d = a.display,
+            e = a.doc,
+            f = document.createDocumentFragment(),
+            g = ob(a.display),
+            h = g.left,
+            i = Math.max(d.sizerWidth, qb(a) - d.sizer.offsetLeft) - g.right,
+            l = b.from(),
+            m = b.to();
+        if (l.line == m.line) k(l.line, l.ch, m.ch);
+        else {
+            var n = ff(e, l.line),
+                o = ff(e, m.line),
+                p = se(n) == se(o),
+                q = k(l.line, l.ch, p ? n.text.length + 1 : null)
+                .end,
+                r = k(m.line, p ? 0 : null, m.ch)
+                .start;
+            p && (q.top < r.top - 2 ? (j(q.right, q.top, null, q.bottom), j(h, r.top, r.left, r.bottom)) : j(q.right, q.top, r.left - q.right, q.bottom)), q.bottom < r.top && j(h, q.bottom, null, r.top)
+        }
+        c.appendChild(f)
+    }
+
+    function hb(a) {
+        if (a.state.focused) {
+            var b = a.display;
+            clearInterval(b.blinker);
+            var c = !0;
+            b.cursorDiv.style.visibility = "", a.options.cursorBlinkRate > 0 ? b.blinker = setInterval(function () {
+                b.cursorDiv.style.visibility = (c = !c) ? "" : "hidden"
+            }, a.options.cursorBlinkRate) : a.options.cursorBlinkRate < 0 && (b.cursorDiv.style.visibility = "hidden")
+        }
+    }
+
+    function ib(a, b) {
+        a.doc.mode.startState && a.doc.frontier < a.display.viewTo && a.state.highlight.set(b, ig(jb, a))
+    }
+
+    function jb(a) {
+        var b = a.doc;
+        if (b.frontier < b.first && (b.frontier = b.first), !(b.frontier >= a.display.viewTo)) {
+            var c = +new Date + a.options.workTime,
+                d = Jd(b.mode, lb(a, b.frontier)),
+                e = [];
+            b.iter(b.frontier, Math.min(b.first + b.size, a.display.viewTo + 500), function (f) {
+                if (b.frontier >= a.display.viewFrom) {
+                    var g = f.styles,
+                        h = f.text.length > a.options.maxHighlightLength,
+                        i = Ke(a, f, h ? Jd(b.mode, d) : d, !0);
+                    f.styles = i.styles;
+                    var j = f.styleClasses,
+                        k = i.classes;
+                    k ? f.styleClasses = k : j && (f.styleClasses = null);
+                    for (var l = !g || g.length != f.styles.length || j != k && (!j || !k || j.bgClass != k.bgClass || j.textClass != k.textClass), m = 0; !l && m < g.length; ++m) l = g[m] != f.styles[m];
+                    l && e.push(b.frontier), f.stateAfter = h ? d : Jd(b.mode, d)
+                } else f.text.length <= a.options.maxHighlightLength && Me(a, f.text, d), f.stateAfter = b.frontier % 5 == 0 ? Jd(b.mode, d) : null;
+                return ++b.frontier, +new Date > c ? (ib(a, a.options.workDelay), !0) : void 0
+            }), e.length && cc(a, function () {
+                for (var b = 0; b < e.length; b++) jc(a, e[b], "text")
+            })
+        }
+    }
+
+    function kb(a, b, c) {
+        for (var d, e, f = a.doc, g = c ? -1 : b - (a.doc.mode.innerMode ? 1e3 : 100), h = b; h > g; --h) {
+            if (h <= f.first) return f.first;
+            var i = ff(f, h - 1);
+            if (i.stateAfter && (!c || h <= f.frontier)) return h;
+            var j = Zf(i.text, null, a.options.tabSize);
+            (null == e || d > j) && (e = h - 1, d = j)
+        }
+        return e
+    }
+
+    function lb(a, b, c) {
+        var d = a.doc,
+            e = a.display;
+        if (!d.mode.startState) return !0;
+        var f = kb(a, b, c),
+            g = f > d.first && ff(d, f - 1)
+            .stateAfter;
+        return g = g ? Jd(d.mode, g) : Kd(d.mode), d.iter(f, b, function (c) {
+            Me(a, c.text, g);
+            var h = f == b - 1 || f % 5 == 0 || f >= e.viewFrom && f < e.viewTo;
+            c.stateAfter = h ? Jd(d.mode, g) : null, ++f
+        }), c && (d.frontier = f), g
+    }
+
+    function mb(a) {
+        return a.lineSpace.offsetTop
+    }
+
+    function nb(a) {
+        return a.mover.offsetHeight - a.lineSpace.offsetHeight
+    }
+
+    function ob(a) {
+        if (a.cachedPaddingH) return a.cachedPaddingH;
+        var b = sg(a.measure, pg("pre", "x")),
+            c = window.getComputedStyle ? window.getComputedStyle(b, null) : b.currentStyle, // why the null: http://bugs.jquery.com/ticket/8635
+            d = {
+                left: parseInt(c.paddingLeft),
+                right: parseInt(c.paddingRight)
+            };
+        return isNaN(d.left) || isNaN(d.right) || (a.cachedPaddingH = d), d
+    }
+
+    function pb(a) {
+        return Tf - a.display.nativeBarWidth
+    }
+
+    function qb(a) {
+        return a.display.scroller.clientWidth - pb(a) - a.display.barWidth
+    }
+
+    function rb(a) {
+        return a.display.scroller.clientHeight - pb(a) - a.display.barHeight
+    }
+
+    function sb(a, b, c) {
+        var d = a.options.lineWrapping,
+            e = d && qb(a);
+        if (!b.measure.heights || d && b.measure.width != e) {
+            var f = b.measure.heights = [];
+            if (d) {
+                b.measure.width = e;
+                for (var g = b.text.firstChild.getClientRects(), h = 0; h < g.length - 1; h++) {
+                    var i = g[h],
+                        j = g[h + 1];
+                    Math.abs(i.bottom - j.bottom) > 2 && f.push((i.bottom + j.top) / 2 - c.top)
+                }
+            }
+            f.push(c.bottom - c.top)
+        }
+    }
+
+    function tb(a, b, c) {
+        if (a.line == b) return {
+            map: a.measure.map,
+            cache: a.measure.cache
+        };
+        for (var d = 0; d < a.rest.length; d++)
+            if (a.rest[d] == b) return {
+                map: a.measure.maps[d],
+                cache: a.measure.caches[d]
+            };
+        for (var d = 0; d < a.rest.length; d++)
+            if (kf(a.rest[d]) > c) return {
+                map: a.measure.maps[d],
+                cache: a.measure.caches[d],
+                before: !0
+            }
+    }
+
+    function ub(a, b) {
+        b = se(b);
+        var c = kf(b),
+            d = a.display.externalMeasured = new gc(a.doc, b, c);
+        d.lineN = c;
+        var e = d.built = Qe(a, d);
+        return d.text = e.pre, sg(a.display.lineMeasure, e.pre), d
+    }
+
+    function vb(a, b, c, d) {
+        return yb(a, xb(a, b), c, d)
+    }
+
+    function wb(a, b) {
+        if (b >= a.display.viewFrom && b < a.display.viewTo) return a.display.view[lc(a, b)];
+        var c = a.display.externalMeasured;
+        return c && b >= c.lineN && b < c.lineN + c.size ? c : void 0
+    }
+
+    function xb(a, b) {
+        var c = kf(b),
+            d = wb(a, c);
+        d && !d.text ? d = null : d && d.changes && (ca(a, d, c, aa(a)), a.curOp.forceUpdate = !0), d || (d = ub(a, b));
+        var e = tb(d, b, c);
+        return {
+            line: b,
+            view: d,
+            rect: null,
+            map: e.map,
+            cache: e.cache,
+            before: e.before,
+            hasHeights: !1
+        }
+    }
+
+    function yb(a, b, c, d, e) {
+        b.before && (c = -1);
+        var g, f = c + (d || "");
+        return b.cache.hasOwnProperty(f) ? g = b.cache[f] : (b.rect || (b.rect = b.view.text.getBoundingClientRect()), b.hasHeights || (sb(a, b.view, b.rect), b.hasHeights = !0), g = Bb(a, b, c, d), g.bogus || (b.cache[f] = g)), {
+            left: g.left,
+            right: g.right,
+            top: e ? g.rtop : g.top,
+            bottom: e ? g.rbottom : g.bottom
+        }
+    }
+
+    function Ab(a, b, c) {
+        for (var d, e, f, g, h = 0; h < a.length; h += 3) {
+            var i = a[h],
+                j = a[h + 1];
+            if (i > b ? (e = 0, f = 1, g = "left") : j > b ? (e = b - i, f = e + 1) : (h == a.length - 3 || b == j && a[h + 3] > b) && (f = j - i, e = f - 1, b >= j && (g = "right")), null != e) {
+                if (d = a[h + 2], i == j && c == (d.insertLeft ? "left" : "right") && (g = c), "left" == c && 0 == e)
+                    for (; h && a[h - 2] == a[h - 3] && a[h - 1].insertLeft;) d = a[(h -= 3) + 2], g = "left";
+                if ("right" == c && e == j - i)
+                    for (; h < a.length - 3 && a[h + 3] == a[h + 4] && !a[h + 5].insertLeft;) d = a[(h += 3) + 2], g = "right";
+                break
+            }
+        }
+        return {
+            node: d,
+            start: e,
+            end: f,
+            collapse: g,
+            coverStart: i,
+            coverEnd: j
+        }
+    }
+
+    function Bb(a, b, c, f) {
+        var l, g = Ab(b.map, c, f),
+            h = g.node,
+            i = g.start,
+            j = g.end,
+            k = g.collapse;
+        if (3 == h.nodeType) {
+            for (var m = 0; 4 > m; m++) {
+                for (; i && og(b.line.text.charAt(g.coverStart + i));) --i;
+                for (; g.coverStart + j < g.coverEnd && og(b.line.text.charAt(g.coverStart + j));) ++j;
+                if (d && 9 > e && 0 == i && j == g.coverEnd - g.coverStart) l = h.parentNode.getBoundingClientRect();
+                else if (d && a.options.lineWrapping) {
+                    var n = qg(h, i, j).getClientRects();
+                    l = n.length ? n["right" == f ? n.length - 1 : 0] : zb
+                } else if (oldff) { // customization here
+                    var w = jQuery(".CodeMirror-line SPAN", b.view.node).get(0);
+                    if (w) {
+                        l = w.getClientRects()[0];
+                    } else {
+                        l = zb;
+                    }
+                } else {
+                    l = qg(h, i, j).getBoundingClientRect() || zb;
+                }
+                if (l.left || l.right || 0 == i) break;
+                j = i, i -= 1, k = "right"
+            }
+            d && 11 > e && (l = Cb(a.display.measure, l))
+        } else {
+            i > 0 && (k = f = "right");
+            var n;
+            l = a.options.lineWrapping && (n = h.getClientRects())
+                .length > 1 ? n["right" == f ? n.length - 1 : 0] : h.getBoundingClientRect()
+        }
+        if (d && 9 > e && !i && (!l || !l.left && !l.right)) {
+            var o = h.parentNode.getClientRects()[0];
+            l = o ? {
+                left: o.left,
+                right: o.left + Sb(a.display),
+                top: o.top,
+                bottom: o.bottom
+            } : zb
+        }
+        for (var p = l.top - b.rect.top, q = l.bottom - b.rect.top, r = (p + q) / 2, s = b.view.measure.heights, m = 0; m < s.length - 1 && !(r < s[m]); m++);
+        var t = m ? s[m - 1] : 0,
+            u = s[m],
+            v = {
+                left: ("right" == k ? l.right : l.left) - b.rect.left,
+                right: ("left" == k ? l.left : l.right) - b.rect.left,
+                top: t,
+                bottom: u
+            };
+        return l.left || l.right || (v.bogus = !0), a.options.singleCursorHeightPerLine || (v.rtop = p, v.rbottom = q), v
+    }
+
+    function Cb(a, b) {
+        if (!window.screen || null == screen.logicalXDPI || screen.logicalXDPI == screen.deviceXDPI || !Mg(a)) return b;
+        var c = screen.logicalXDPI / screen.deviceXDPI,
+            d = screen.logicalYDPI / screen.deviceYDPI;
+        return {
+            left: b.left * c,
+            right: b.right * c,
+            top: b.top * d,
+            bottom: b.bottom * d
+        }
+    }
+
+    function Db(a) {
+        if (a.measure && (a.measure.cache = {}, a.measure.heights = null, a.rest))
+            for (var b = 0; b < a.rest.length; b++) a.measure.caches[b] = {}
+    }
+
+    function Eb(a) {
+        a.display.externalMeasure = null, rg(a.display.lineMeasure);
+        for (var b = 0; b < a.display.view.length; b++) Db(a.display.view[b])
+    }
+
+    function Fb(a) {
+        Eb(a), a.display.cachedCharWidth = a.display.cachedTextHeight = a.display.cachedPaddingH = null, a.options.lineWrapping || (a.display.maxLineChanged = !0), a.display.lineNumChars = null
+    }
+
+    function Gb() {
+        return window.pageXOffset || (document.documentElement || document.body)
+            .scrollLeft
+    }
+
+    function Hb() {
+        return window.pageYOffset || (document.documentElement || document.body)
+            .scrollTop
+    }
+
+    function Ib(a, b, c, d) {
+        if (b.widgets)
+            for (var e = 0; e < b.widgets.length; ++e)
+                if (b.widgets[e].above) {
+                    var f = Ae(b.widgets[e]);
+                    c.top += f, c.bottom += f
+                }
+        if ("line" == d) return c;
+        d || (d = "local");
+        var g = mf(b);
+        if ("local" == d ? g += mb(a.display) : g -= a.display.viewOffset, "page" == d || "window" == d) {
+            var h = a.display.lineSpace.getBoundingClientRect();
+            g += h.top + ("window" == d ? 0 : Hb());
+            var i = h.left + ("window" == d ? 0 : Gb());
+            c.left += i, c.right += i
+        }
+        return c.top += g, c.bottom += g, c
+    }
+
+    function Jb(a, b, c) {
+        if ("div" == c) return b;
+        var d = b.left,
+            e = b.top;
+        if ("page" == c) d -= Gb(), e -= Hb();
+        else if ("local" == c || !c) {
+            var f = a.display.sizer.getBoundingClientRect();
+            d += f.left, e += f.top
+        }
+        var g = a.display.lineSpace.getBoundingClientRect();
+        return {
+            left: d - g.left,
+            top: e - g.top
+        }
+    }
+
+    function Kb(a, b, c, d, e) {
+        return d || (d = ff(a.doc, b.line)), Ib(a, d, vb(a, d, b.ch, e), c)
+    }
+
+    function Lb(a, b, c, d, e, f) {
+        function g(b, g) {
+            var h = yb(a, e, b, g ? "right" : "left", f);
+            return g ? h.left = h.right : h.right = h.left, Ib(a, d, h, c)
+        }
+
+        function h(a, b) {
+            var c = i[b],
+                d = c.level % 2;
+            return a == Pg(c) && b && c.level < i[b - 1].level ? (c = i[--b], a = Qg(c) - (c.level % 2 ? 0 : 1), d = !0) : a == Qg(c) && b < i.length - 1 && c.level < i[b + 1].level && (c = i[++b], a = Pg(c) - c.level % 2, d = !1), d && a == c.to && a > c.from ? g(a - 1) : g(a, d)
+        }
+        d = d || ff(a.doc, b.line), e || (e = xb(a, d));
+        var i = nf(d),
+            j = b.ch;
+        if (!i) return g(j);
+        var k = Yg(i, j),
+            l = h(j, k);
+        return null != Xg && (l.other = h(j, Xg)), l
+    }
+
+    function Mb(a, b) {
+        var c = 0,
+            b = Oa(a.doc, b);
+        a.options.lineWrapping || (c = Sb(a.display) * b.ch);
+        var d = ff(a.doc, b.line),
+            e = mf(d) + mb(a.display);
+        return {
+            left: c,
+            right: c,
+            top: e,
+            bottom: e + d.height
+        }
+    }
+
+    function Nb(a, b, c, d) {
+        var e = oa(a, b);
+        return e.xRel = d, c && (e.outside = !0), e
+    }
+
+    function Ob(a, b, c) {
+        var d = a.doc;
+        if (c += a.display.viewOffset, 0 > c) return Nb(d.first, 0, !0, -1);
+        var e = lf(d, c),
+            f = d.first + d.size - 1;
+        if (e > f) return Nb(d.first + d.size - 1, ff(d, f)
+            .text.length, !0, 1);
+        0 > b && (b = 0);
+        for (var g = ff(d, e);;) {
+            var h = Pb(a, g, e, b, c),
+                i = qe(g),
+                j = i && i.find(0, !0);
+            if (!i || !(h.ch > j.from.ch || h.ch == j.from.ch && h.xRel > 0)) return h;
+            e = kf(g = j.to.line)
+        }
+    }
+
+    function Pb(a, b, c, d, e) {
+        function j(d) {
+            var e = Lb(a, oa(c, d), "line", b, i);
+            return g = !0, f > e.bottom ? e.left - h : f < e.top ? e.left + h : (g = !1, e.left)
+        }
+        var f = e - mf(b),
+            g = !1,
+            h = 2 * a.display.wrapper.clientWidth,
+            i = xb(a, b),
+            k = nf(b),
+            l = b.text.length,
+            m = Rg(b),
+            n = Sg(b),
+            o = j(m),
+            p = g,
+            q = j(n),
+            r = g;
+        if (d > q) return Nb(c, n, r, 1);
+        for (;;) {
+            if (k ? n == m || n == $g(b, m, 1) : 1 >= n - m) {
+                for (var s = o > d || q - d >= d - o ? m : n, t = d - (s == m ? o : q); og(b.text.charAt(s));) ++s;
+                var u = Nb(c, s, s == m ? p : r, -1 > t ? -1 : t > 1 ? 1 : 0);
+                return u
+            }
+            var v = Math.ceil(l / 2),
+                w = m + v;
+            if (k) {
+                w = m;
+                for (var x = 0; v > x; ++x) w = $g(b, w, 1)
+            }
+            var y = j(w);
+            y > d ? (n = w, q = y, (r = g) && (q += 1e3), l = v) : (m = w, o = y, p = g, l -= v)
+        }
+    }
+
+    function Rb(a) {
+        if (null != a.cachedTextHeight) return a.cachedTextHeight;
+        if (null == Qb) {
+            Qb = pg("pre");
+            for (var b = 0; 49 > b; ++b) Qb.appendChild(document.createTextNode("x")), Qb.appendChild(pg("br"));
+            Qb.appendChild(document.createTextNode("x"))
+        }
+        sg(a.measure, Qb);
+        var c = Qb.offsetHeight / 50;
+        return c > 3 && (a.cachedTextHeight = c), rg(a.measure), c || 1
+    }
+
+    function Sb(a) {
+        if (null != a.cachedCharWidth) return a.cachedCharWidth;
+        var b = pg("span", "xxxxxxxxxx"),
+            c = pg("pre", [b]);
+        sg(a.measure, c);
+        var d = b.getBoundingClientRect(),
+            e = (d.right - d.left) / 10;
+        return e > 2 && (a.cachedCharWidth = e), e || 10
+    }
+
+    function Vb(a) {
+        a.curOp = {
+            cm: a,
+            viewChanged: !1,
+            startHeight: a.doc.height,
+            forceUpdate: !1,
+            updateInput: null,
+            typing: !1,
+            changeObjs: null,
+            cursorActivityHandlers: null,
+            cursorActivityCalled: 0,
+            selectionChanged: !1,
+            updateMaxLine: !1,
+            scrollLeft: null,
+            scrollTop: null,
+            scrollToPos: null,
+            focus: !1,
+            id: ++Ub
+        }, Tb ? Tb.ops.push(a.curOp) : a.curOp.ownsGroup = Tb = {
+            ops: [a.curOp],
+            delayedCallbacks: []
+        }
+    }
+
+    function Wb(a) {
+        var b = a.delayedCallbacks,
+            c = 0;
+        do {
+            for (; c < b.length; c++) b[c].call(null);
+            for (var d = 0; d < a.ops.length; d++) {
+                var e = a.ops[d];
+                if (e.cursorActivityHandlers)
+                    for (; e.cursorActivityCalled < e.cursorActivityHandlers.length;) e.cursorActivityHandlers[e.cursorActivityCalled++].call(null, e.cm)
+            }
+        } while (c < b.length)
+    }
+
+    function Xb(a) {
+        var b = a.curOp,
+            c = b.ownsGroup;
+        if (c) try {
+            Wb(c)
+        } finally {
+            Tb = null;
+            for (var d = 0; d < c.ops.length; d++) c.ops[d].cm.curOp = null;
+            Yb(c)
+        }
+    }
+
+    function Yb(a) {
+        for (var b = a.ops, c = 0; c < b.length; c++) Zb(b[c]);
+        for (var c = 0; c < b.length; c++) $b(b[c]);
+        for (var c = 0; c < b.length; c++) _b(b[c]);
+        for (var c = 0; c < b.length; c++) ac(b[c]);
+        for (var c = 0; c < b.length; c++) bc(b[c])
+    }
+
+    function Zb(a) {
+        var b = a.cm,
+            c = b.display;
+        V(b), a.updateMaxLine && H(b), a.mustUpdate = a.viewChanged || a.forceUpdate || null != a.scrollTop || a.scrollToPos && (a.scrollToPos.from.line < c.viewFrom || a.scrollToPos.to.line >= c.viewTo) || c.maxLineChanged && b.options.lineWrapping, a.update = a.mustUpdate && new U(b, a.mustUpdate && {
+            top: a.scrollTop,
+            ensure: a.scrollToPos
+        }, a.forceUpdate)
+    }
+
+    function $b(a) {
+        a.updatedDisplay = a.mustUpdate && W(a.cm, a.update)
+    }
+
+    function _b(a) {
+        var b = a.cm,
+            c = b.display;
+        a.updatedDisplay && $(b), a.barMeasure = J(b), c.maxLineChanged && !b.options.lineWrapping && (a.adjustWidthTo = vb(b, c.maxLine, c.maxLine.text.length)
+            .left + 3, b.display.sizerWidth = a.adjustWidthTo, a.barMeasure.scrollWidth = Math.max(c.scroller.clientWidth, c.sizer.offsetLeft + a.adjustWidthTo + pb(b) + b.display.barWidth), a.maxScrollLeft = Math.max(0, c.sizer.offsetLeft + a.adjustWidthTo - qb(b))), (a.updatedDisplay || a.selectionChanged) && (a.preparedSelection = c.input.prepareSelection())
+    }
+
+    function ac(a) {
+        var b = a.cm;
+        null != a.adjustWidthTo && (b.display.sizer.style.minWidth = a.adjustWidthTo + "px", a.maxScrollLeft < b.doc.scrollLeft && Ic(b, Math.min(b.display.scroller.scrollLeft, a.maxScrollLeft), !0), b.display.maxLineChanged = !1), a.preparedSelection && b.display.input.showSelection(a.preparedSelection), a.updatedDisplay && Z(b, a.barMeasure), (a.updatedDisplay || a.startHeight != b.doc.height) && N(b, a.barMeasure), a.selectionChanged && hb(b), b.state.focused && a.updateInput && b.display.input.reset(a.typing), a.focus && a.focus == ug() && ta(a.cm)
+    }
+
+    function bc(a) {
+        var b = a.cm,
+            c = b.display,
+            d = b.doc;
+        if (a.updatedDisplay && X(b, a.update), null == c.wheelStartX || null == a.scrollTop && null == a.scrollLeft && !a.scrollToPos || (c.wheelStartX = c.wheelStartY = null), null == a.scrollTop || c.scroller.scrollTop == a.scrollTop && !a.forceScroll || (d.scrollTop = Math.max(0, Math.min(c.scroller.scrollHeight - c.scroller.clientHeight, a.scrollTop)), c.scrollbars.setScrollTop(d.scrollTop), c.scroller.scrollTop = d.scrollTop), null == a.scrollLeft || c.scroller.scrollLeft == a.scrollLeft && !a.forceScroll || (d.scrollLeft = Math.max(0, Math.min(c.scroller.scrollWidth - qb(b), a.scrollLeft)), c.scrollbars.setScrollLeft(d.scrollLeft), c.scroller.scrollLeft = d.scrollLeft, Q(b)), a.scrollToPos) {
+            var e = pd(b, Oa(d, a.scrollToPos.from), Oa(d, a.scrollToPos.to), a.scrollToPos.margin);
+            a.scrollToPos.isCursor && b.state.focused && od(b, e)
+        }
+        var f = a.maybeHiddenMarkers,
+            g = a.maybeUnhiddenMarkers;
+        if (f)
+            for (var h = 0; h < f.length; ++h) f[h].lines.length || Lf(f[h], "hide");
+        if (g)
+            for (var h = 0; h < g.length; ++h) g[h].lines.length && Lf(g[h], "unhide");
+        c.wrapper.offsetHeight && (d.scrollTop = b.display.scroller.scrollTop), a.changeObjs && Lf(b, "changes", b, a.changeObjs), a.update && a.update.finish()
+    }
+
+    function cc(a, b) {
+        if (a.curOp) return b();
+        Vb(a);
+        try {
+            return b()
+        } finally {
+            Xb(a)
+        }
+    }
+
+    function dc(a, b) {
+        return function () {
+            if (a.curOp) return b.apply(a, arguments);
+            Vb(a);
+            try {
+                return b.apply(a, arguments)
+            } finally {
+                Xb(a)
+            }
+        }
+    }
+
+    function ec(a) {
+        return function () {
+            if (this.curOp) return a.apply(this, arguments);
+            Vb(this);
+            try {
+                return a.apply(this, arguments)
+            } finally {
+                Xb(this)
+            }
+        }
+    }
+
+    function fc(a) {
+        return function () {
+            var b = this.cm;
+            if (!b || b.curOp) return a.apply(this, arguments);
+            Vb(b);
+            try {
+                return a.apply(this, arguments)
+            } finally {
+                Xb(b)
+            }
+        }
+    }
+
+    function gc(a, b, c) {
+        this.line = b, this.rest = te(b), this.size = this.rest ? kf(bg(this.rest)) - c + 1 : 1, this.node = this.text = null, this.hidden = we(a, b)
+    }
+
+    function hc(a, b, c) {
+        for (var e, d = [], f = b; c > f; f = e) {
+            var g = new gc(a.doc, ff(a.doc, f), f);
+            e = f + g.size, d.push(g)
+        }
+        return d
+    }
+
+    function ic(a, b, c, d) {
+        null == b && (b = a.doc.first), null == c && (c = a.doc.first + a.doc.size), d || (d = 0);
+        var e = a.display;
+        if (d && c < e.viewTo && (null == e.updateLineNumbers || e.updateLineNumbers > b) && (e.updateLineNumbers = b), a.curOp.viewChanged = !0, b >= e.viewTo) u && ue(a.doc, b) < e.viewTo && kc(a);
+        else if (c <= e.viewFrom) u && ve(a.doc, c + d) > e.viewFrom ? kc(a) : (e.viewFrom += d, e.viewTo += d);
+        else if (b <= e.viewFrom && c >= e.viewTo) kc(a);
+        else if (b <= e.viewFrom) {
+            var f = mc(a, c, c + d, 1);
+            f ? (e.view = e.view.slice(f.index), e.viewFrom = f.lineN, e.viewTo += d) : kc(a)
+        } else if (c >= e.viewTo) {
+            var f = mc(a, b, b, -1);
+            f ? (e.view = e.view.slice(0, f.index), e.viewTo = f.lineN) : kc(a)
+        } else {
+            var g = mc(a, b, b, -1),
+                h = mc(a, c, c + d, 1);
+            g && h ? (e.view = e.view.slice(0, g.index)
+                .concat(hc(a, g.lineN, h.lineN))
+                .concat(e.view.slice(h.index)), e.viewTo += d) : kc(a)
+        }
+        var i = e.externalMeasured;
+        i && (c < i.lineN ? i.lineN += d : b < i.lineN + i.size && (e.externalMeasured = null))
+    }
+
+    function jc(a, b, c) {
+        a.curOp.viewChanged = !0;
+        var d = a.display,
+            e = a.display.externalMeasured;
+        if (e && b >= e.lineN && b < e.lineN + e.size && (d.externalMeasured = null), !(b < d.viewFrom || b >= d.viewTo)) {
+            var f = d.view[lc(a, b)];
+            if (null != f.node) {
+                var g = f.changes || (f.changes = []); - 1 == dg(g, c) && g.push(c)
+            }
+        }
+    }
+
+    function kc(a) {
+        a.display.viewFrom = a.display.viewTo = a.doc.first, a.display.view = [], a.display.viewOffset = 0
+    }
+
+    function lc(a, b) {
+        if (b >= a.display.viewTo) return null;
+        if (b -= a.display.viewFrom, 0 > b) return null;
+        for (var c = a.display.view, d = 0; d < c.length; d++)
+            if (b -= c[d].size, 0 > b) return d
+    }
+
+    function mc(a, b, c, d) {
+        var f, e = lc(a, b),
+            g = a.display.view;
+        if (!u || c == a.doc.first + a.doc.size) return {
+            index: e,
+            lineN: c
+        };
+        for (var h = 0, i = a.display.viewFrom; e > h; h++) i += g[h].size;
+        if (i != b) {
+            if (d > 0) {
+                if (e == g.length - 1) return null;
+                f = i + g[e].size - b, e++
+            } else f = i - b;
+            b += f, c += f
+        }
+        for (; ue(a.doc, c) != c;) {
+            if (e == (0 > d ? 0 : g.length - 1)) return null;
+            c += d * g[e - (0 > d ? 1 : 0)].size, e += d
+        }
+        return {
+            index: e,
+            lineN: c
+        }
+    }
+
+    function nc(a, b, c) {
+        var d = a.display,
+            e = d.view;
+        0 == e.length || b >= d.viewTo || c <= d.viewFrom ? (d.view = hc(a, b, c), d.viewFrom = b) : (d.viewFrom > b ? d.view = hc(a, b, d.viewFrom)
+            .concat(d.view) : d.viewFrom < b && (d.view = d.view.slice(lc(a, b))), d.viewFrom = b, d.viewTo < c ? d.view = d.view.concat(hc(a, d.viewTo, c)) : d.viewTo > c && (d.view = d.view.slice(0, lc(a, c)))), d.viewTo = c
+    }
+
+    function oc(a) {
+        for (var b = a.display.view, c = 0, d = 0; d < b.length; d++) {
+            var e = b[d];
+            e.hidden || e.node && !e.changes || ++c
+        }
+        return c
+    }
+
+    function pc(a) {
+        function g() {
+            b.activeTouch && (c = setTimeout(function () {
+                b.activeTouch = null
+            }, 1e3), f = b.activeTouch, f.end = +new Date)
+        }
+
+        function h(a) {
+            if (1 != a.touches.length) return !1;
+            var b = a.touches[0];
+            return b.radiusX <= 1 && b.radiusY <= 1
+        }
+
+        function i(a, b) {
+            if (null == b.left) return !0;
+            var c = b.left - a.left,
+                d = b.top - a.top;
+            return c * c + d * d > 400
+        }
+        var b = a.display;
+        Jf(b.scroller, "mousedown", dc(a, uc)), d && 11 > e ? Jf(b.scroller, "dblclick", dc(a, function (b) {
+            if (!Pf(a, b)) {
+                var c = tc(a, b);
+                if (c && !Bc(a, b) && !sc(a.display, b)) {
+                    Df(b);
+                    var d = a.findWordAt(c);
+                    Ta(a.doc, d.anchor, d.head)
+                }
+            }
+        })) : Jf(b.scroller, "dblclick", function (b) {
+            Pf(a, b) || Df(b)
+        }), s || Jf(b.scroller, "contextmenu", function (b) {
+            _c(a, b)
+        });
+        var c, f = {
+            end: 0
+        };
+        Jf(b.scroller, "touchstart", function (a) {
+            if (!h(a)) {
+                clearTimeout(c);
+                var d = +new Date;
+                b.activeTouch = {
+                    start: d,
+                    moved: !1,
+                    prev: d - f.end <= 300 ? f : null
+                }, 1 == a.touches.length && (b.activeTouch.left = a.touches[0].pageX, b.activeTouch.top = a.touches[0].pageY)
+            }
+        }), Jf(b.scroller, "touchmove", function () {
+            b.activeTouch && (b.activeTouch.moved = !0)
+        }), Jf(b.scroller, "touchend", function (c) {
+            var d = b.activeTouch;
+            if (d && !sc(b, c) && null != d.left && !d.moved && new Date - d.start < 300) {
+                var f, e = a.coordsChar(b.activeTouch, "page");
+                f = !d.prev || i(d, d.prev) ? new Ka(e, e) : !d.prev.prev || i(d, d.prev.prev) ? a.findWordAt(e) : new Ka(oa(e.line, 0), Oa(a.doc, oa(e.line + 1, 0))), a.setSelection(f.anchor, f.head), a.focus(), Df(c)
+            }
+            g()
+        }), Jf(b.scroller, "touchcancel", g), Jf(b.scroller, "scroll", function () {
+            b.scroller.clientHeight && (Hc(a, b.scroller.scrollTop), Ic(a, b.scroller.scrollLeft, !0), Lf(a, "scroll", a))
+        }), Jf(b.scroller, "mousewheel", function (b) {
+            Mc(a, b)
+        }), Jf(b.scroller, "DOMMouseScroll", function (b) {
+            Mc(a, b)
+        }), Jf(b.wrapper, "scroll", function () {
+            b.wrapper.scrollTop = b.wrapper.scrollLeft = 0
+        }), b.dragFunctions = {
+            enter: function (b) {
+                Pf(a, b) || Gf(b)
+            },
+            over: function (b) {
+                Pf(a, b) || (Fc(a, b), Gf(b))
+            },
+            start: function (b) {
+                Ec(a, b)
+            },
+            drop: dc(a, Dc),
+            leave: function () {
+                Gc(a)
+            }
+        };
+        var j = b.input.getField();
+        Jf(j, "keyup", function (b) {
+            Wc.call(a, b)
+        }), Jf(j, "keydown", dc(a, Uc)), Jf(j, "keypress", dc(a, Xc)), Jf(j, "focus", ig(Zc, a)), Jf(j, "blur", ig($c, a))
+    }
+
+    function qc(a, b, c) {
+        var d = c && c != v.Init;
+        if (!b != !d) {
+            var e = a.display.dragFunctions,
+                f = b ? Jf : Kf;
+            f(a.display.scroller, "dragstart", e.start), f(a.display.scroller, "dragenter", e.enter), f(a.display.scroller, "dragover", e.over), f(a.display.scroller, "dragleave", e.leave), f(a.display.scroller, "drop", e.drop)
+        }
+    }
+
+    function rc(a) {
+        var b = a.display;
+        (b.lastWrapHeight != b.wrapper.clientHeight || b.lastWrapWidth != b.wrapper.clientWidth) && (b.cachedCharWidth = b.cachedTextHeight = b.cachedPaddingH = null, b.scrollbarsClipped = !1, a.setSize())
+    }
+
+    function sc(a, b) {
+        for (var c = Hf(b); c != a.wrapper; c = c.parentNode)
+            if (!c || 1 == c.nodeType && "true" == c.getAttribute("cm-ignore-events") || c.parentNode == a.sizer && c != a.mover) return !0
+    }
+
+    function tc(a, b, c, d) {
+        var e = a.display;
+        if (!c && "true" == Hf(b)
+            .getAttribute("cm-not-content")) return null;
+        var f, g, h = e.lineSpace.getBoundingClientRect();
+        try {
+            f = b.clientX - h.left, g = b.clientY - h.top
+        } catch (b) {
+            return null
+        }
+        var j, i = Ob(a, f, g);
+        if (d && 1 == i.xRel && (j = ff(a.doc, i.line)
+                .text)
+            .length == i.ch) {
+            var k = Zf(j, j.length, a.options.tabSize) - j.length;
+            i = oa(i.line, Math.max(0, Math.round((f - ob(a.display)
+                .left) / Sb(a.display)) - k))
+        }
+        return i
+    }
+
+    function uc(a) {
+        var b = this,
+            c = b.display;
+        if (!(c.activeTouch && c.input.supportsTouch() || Pf(b, a))) {
+            if (c.shift = a.shiftKey, sc(c, a)) return void(f || (c.scroller.draggable = !1, setTimeout(function () {
+                c.scroller.draggable = !0
+            }, 100)));
+            if (!Bc(b, a)) {
+                var d = tc(b, a);
+                switch (window.focus(), If(a)) {
+                case 1:
+                    b.state.selectingText ? b.state.selectingText(a) : d ? xc(b, a, d) : Hf(a) == c.scroller && Df(a);
+                    break;
+                case 2:
+                    f && (b.state.lastMiddleDown = +new Date), d && Ta(b.doc, d), setTimeout(function () {
+                        c.input.focus()
+                    }, 20), Df(a);
+                    break;
+                case 3:
+                    s ? _c(b, a) : Yc(b)
+                }
+            }
+        }
+    }
+
+    function xc(a, b, c) {
+        d ? setTimeout(ig(ta, a), 0) : a.curOp.focus = ug();
+        var f, e = +new Date;
+        wc && wc.time > e - 400 && 0 == pa(wc.pos, c) ? f = "triple" : vc && vc.time > e - 400 && 0 == pa(vc.pos, c) ? (f = "double", wc = {
+            time: e,
+            pos: c
+        }) : (f = "single", vc = {
+            time: e,
+            pos: c
+        });
+        var i, g = a.doc.sel,
+            h = o ? b.metaKey : b.ctrlKey;
+        a.options.dragDrop && Dg && !ua(a) && "single" == f && (i = g.contains(c)) > -1 && (pa((i = g.ranges[i])
+            .from(), c) < 0 || c.xRel > 0) && (pa(i.to(), c) > 0 || c.xRel < 0) ? yc(a, b, c, h) : zc(a, b, c, f, h)
+    }
+
+    function yc(a, b, c, g) {
+        var h = a.display,
+            i = +new Date,
+            j = dc(a, function (k) {
+                f && (h.scroller.draggable = !1), a.state.draggingText = !1, Kf(document, "mouseup", j), Kf(h.scroller, "drop", j), Math.abs(b.clientX - k.clientX) + Math.abs(b.clientY - k.clientY) < 10 && (Df(k), !g && +new Date - 200 < i && Ta(a.doc, c), f || d && 9 == e ? setTimeout(function () {
+                    document.body.focus(), h.input.focus()
+                }, 20) : h.input.focus())
+            });
+        f && (h.scroller.draggable = !0), a.state.draggingText = j, h.scroller.dragDrop && h.scroller.dragDrop(), Jf(document, "mouseup", j), Jf(h.scroller, "drop", j)
+    }
+
+    function zc(a, b, c, d, e) {
+        function o(b) {
+            if (0 != pa(n, b))
+                if (n = b, "rect" == d) {
+                    for (var e = [], f = a.options.tabSize, k = Zf(ff(g, c.line)
+                            .text, c.ch, f), l = Zf(ff(g, b.line)
+                            .text, b.ch, f), m = Math.min(k, l), o = Math.max(k, l), p = Math.min(c.line, b.line), q = Math.min(a.lastLine(), Math.max(c.line, b.line)); q >= p; p++) {
+                        var r = ff(g, p)
+                            .text,
+                            s = $f(r, m, f);
+                        m == o ? e.push(new Ka(oa(p, s), oa(p, s))) : r.length > s && e.push(new Ka(oa(p, s), oa(p, $f(r, o, f))))
+                    }
+                    e.length || e.push(new Ka(c, c)), Za(g, La(j.ranges.slice(0, i)
+                        .concat(e), i), {
+                        origin: "*mouse",
+                        scroll: !1
+                    }), a.scrollIntoView(b)
+                } else {
+                    var t = h,
+                        u = t.anchor,
+                        v = b;
+                    if ("single" != d) {
+                        if ("double" == d) var w = a.findWordAt(b);
+                        else var w = new Ka(oa(b.line, 0), Oa(g, oa(b.line + 1, 0)));
+                        pa(w.anchor, u) > 0 ? (v = w.head, u = sa(t.from(), w.anchor)) : (v = w.anchor, u = ra(t.to(), w.head))
+                    }
+                    var e = j.ranges.slice(0);
+                    e[i] = new Ka(Oa(g, u), v), Za(g, La(e, i), Wf)
+                }
+        }
+
+        function r(b) {
+            var c = ++q,
+                e = tc(a, b, !0, "rect" == d);
+            if (e)
+                if (0 != pa(e, n)) {
+                    a.curOp.focus = ug(), o(e);
+                    var h = P(f, g);
+                    (e.line >= h.to || e.line < h.from) && setTimeout(dc(a, function () {
+                        q == c && r(b)
+                    }), 150)
+                } else {
+                    var i = b.clientY < p.top ? -20 : b.clientY > p.bottom ? 20 : 0;
+                    i && setTimeout(dc(a, function () {
+                        q == c && (f.scroller.scrollTop += i, r(b))
+                    }), 50)
+                }
+        }
+
+        function s(b) {
+            a.state.selectingText = !1, q = 1 / 0, Df(b), f.input.focus(), Kf(document, "mousemove", t), Kf(document, "mouseup", u), g.history.lastSelOrigin = null
+        }
+        var f = a.display,
+            g = a.doc;
+        Df(b);
+        var h, i, j = g.sel,
+            k = j.ranges;
+        if (e && !b.shiftKey ? (i = g.sel.contains(c), h = i > -1 ? k[i] : new Ka(c, c)) : (h = g.sel.primary(), i = g.sel.primIndex), b.altKey) d = "rect", e || (h = new Ka(c, c)), c = tc(a, b, !0, !0), i = -1;
+        else if ("double" == d) {
+            var l = a.findWordAt(c);
+            h = a.display.shift || g.extend ? Sa(g, h, l.anchor, l.head) : l
+        } else if ("triple" == d) {
+            var m = new Ka(oa(c.line, 0), Oa(g, oa(c.line + 1, 0)));
+            h = a.display.shift || g.extend ? Sa(g, h, m.anchor, m.head) : m
+        } else h = Sa(g, h, c);
+        e ? -1 == i ? (i = k.length, Za(g, La(k.concat([h]), i), {
+            scroll: !1,
+            origin: "*mouse"
+        })) : k.length > 1 && k[i].empty() && "single" == d && !b.shiftKey ? (Za(g, La(k.slice(0, i)
+            .concat(k.slice(i + 1)), 0), {
+            scroll: !1,
+            origin: "*mouse"
+        }), j = g.sel) : Va(g, i, h, Wf) : (i = 0, Za(g, new Ja([h], 0), Wf), j = g.sel);
+        var n = c,
+            p = f.wrapper.getBoundingClientRect(),
+            q = 0,
+            t = dc(a, function (a) {
+                If(a) ? r(a) : s(a)
+            }),
+            u = dc(a, s);
+        a.state.selectingText = u, Jf(document, "mousemove", t), Jf(document, "mouseup", u)
+    }
+
+    function Ac(a, b, c, d, e) {
+        try {
+            var f = b.clientX,
+                g = b.clientY
+        } catch (b) {
+            return !1
+        }
+        if (f >= Math.floor(a.display.gutters.getBoundingClientRect()
+                .right)) return !1;
+        d && Df(b);
+        var h = a.display,
+            i = h.lineDiv.getBoundingClientRect();
+        if (g > i.bottom || !Rf(a, c)) return Ff(b);
+        g -= i.top - h.viewOffset;
+        for (var j = 0; j < a.options.gutters.length; ++j) {
+            var k = h.gutters.childNodes[j];
+            if (k && k.getBoundingClientRect()
+                .right >= f) {
+                var l = lf(a.doc, g),
+                    m = a.options.gutters[j];
+                return e(a, c, a, l, m, b), Ff(b)
+            }
+        }
+    }
+
+    function Bc(a, b) {
+        return Ac(a, b, "gutterClick", !0, Nf)
+    }
+
+    function Dc(a) {
+        var b = this;
+        if (Gc(b), !Pf(b, a) && !sc(b.display, a)) {
+            Df(a), d && (Cc = +new Date);
+            var c = tc(b, a, !0),
+                e = a.dataTransfer.files;
+            if (c && !ua(b))
+                if (e && e.length && window.FileReader && window.File)
+                    for (var f = e.length, g = Array(f), h = 0, i = function (a, d) {
+                            var e = new FileReader;
+                            e.onload = dc(b, function () {
+                                if (g[d] = e.result, ++h == f) {
+                                    c = Oa(b.doc, c);
+                                    var a = {
+                                        from: c,
+                                        to: c,
+                                        text: b.doc.splitLines(g.join(b.doc.lineSeparator())),
+                                        origin: "paste"
+                                    };
+                                    hd(b.doc, a), Ya(b.doc, Ma(c, bd(a)))
+                                }
+                            }), e.readAsText(a)
+                        }, j = 0; f > j; ++j) i(e[j], j);
+                else {
+                    if (b.state.draggingText && b.doc.sel.contains(c) > -1) return b.state.draggingText(a), void setTimeout(function () {
+                        b.display.input.focus()
+                    }, 20);
+                    try {
+                        var g = a.dataTransfer.getData("Text");
+                        if (g) {
+                            if (b.state.draggingText && !(o ? a.altKey : a.ctrlKey)) var k = b.listSelections();
+                            if ($a(b.doc, Ma(c, c)), k)
+                                for (var j = 0; j < k.length; ++j) nd(b.doc, "", k[j].anchor, k[j].head, "drag");
+                            b.replaceSelection(g, "around", "paste"), b.display.input.focus()
+                        }
+                    } catch (a) {}
+                }
+        }
+    }
+
+    function Ec(a, b) {
+        if (d && (!a.state.draggingText || +new Date - Cc < 100)) return void Gf(b);
+        if (!Pf(a, b) && !sc(a.display, b) && (b.dataTransfer.setData("Text", a.getSelection()), b.dataTransfer.setDragImage && !j)) {
+            var c = pg("img", null, null, "position: fixed; left: 0; top: 0;");
+            c.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==", i && (c.width = c.height = 1, a.display.wrapper.appendChild(c), c._top = c.offsetTop), b.dataTransfer.setDragImage(c, 0, 0), i && c.parentNode.removeChild(c)
+        }
+    }
+
+    function Fc(a, b) {
+        var c = tc(a, b);
+        if (c) {
+            var d = document.createDocumentFragment();
+            fb(a, c, d), a.display.dragCursor || (a.display.dragCursor = pg("div", null, "CodeMirror-cursors CodeMirror-dragcursors"), a.display.lineSpace.insertBefore(a.display.dragCursor, a.display.cursorDiv)), sg(a.display.dragCursor, d)
+        }
+    }
+
+    function Gc(a) {
+        a.display.dragCursor && (a.display.lineSpace.removeChild(a.display.dragCursor), a.display.dragCursor = null)
+    }
+
+    function Hc(b, c) {
+        Math.abs(b.doc.scrollTop - c) < 2 || (b.doc.scrollTop = c, a || Y(b, {
+            top: c
+        }), b.display.scroller.scrollTop != c && (b.display.scroller.scrollTop = c), b.display.scrollbars.setScrollTop(c), a && Y(b), ib(b, 100))
+    }
+
+    function Ic(a, b, c) {
+        (c ? b == a.doc.scrollLeft : Math.abs(a.doc.scrollLeft - b) < 2) || (b = Math.min(b, a.display.scroller.scrollWidth - a.display.scroller.clientWidth), a.doc.scrollLeft = b, Q(a), a.display.scroller.scrollLeft != b && (a.display.scroller.scrollLeft = b), a.display.scrollbars.setScrollLeft(b))
+    }
+
+    function Mc(b, c) {
+        var d = Lc(c),
+            e = d.x,
+            g = d.y,
+            h = b.display,
+            j = h.scroller;
+        if (e && j.scrollWidth > j.clientWidth || g && j.scrollHeight > j.clientHeight) {
+            if (g && o && f) a: for (var k = c.target, l = h.view; k != j; k = k.parentNode)
+                for (var m = 0; m < l.length; m++)
+                    if (l[m].node == k) {
+                        b.display.currentWheelTarget = k;
+                        break a
+                    }
+            if (e && !a && !i && null != Kc) return g && Hc(b, Math.max(0, Math.min(j.scrollTop + g * Kc, j.scrollHeight - j.clientHeight))), Ic(b, Math.max(0, Math.min(j.scrollLeft + e * Kc, j.scrollWidth - j.clientWidth))), Df(c), void(h.wheelStartX = null);
+            if (g && null != Kc) {
+                var n = g * Kc,
+                    p = b.doc.scrollTop,
+                    q = p + h.wrapper.clientHeight;
+                0 > n ? p = Math.max(0, p + n - 50) : q = Math.min(b.doc.height, q + n + 50), Y(b, {
+                    top: p,
+                    bottom: q
+                })
+            }
+            20 > Jc && (null == h.wheelStartX ? (h.wheelStartX = j.scrollLeft, h.wheelStartY = j.scrollTop, h.wheelDX = e, h.wheelDY = g, setTimeout(function () {
+                if (null != h.wheelStartX) {
+                    var a = j.scrollLeft - h.wheelStartX,
+                        b = j.scrollTop - h.wheelStartY,
+                        c = b && h.wheelDY && b / h.wheelDY || a && h.wheelDX && a / h.wheelDX;
+                    h.wheelStartX = h.wheelStartY = null, c && (Kc = (Kc * Jc + c) / (Jc + 1), ++Jc)
+                }
+            }, 200)) : (h.wheelDX += e, h.wheelDY += g))
+        }
+    }
+
+    function Nc(a, b, c) {
+        if ("string" == typeof b && (b = Ld[b], !b)) return !1;
+        a.display.input.ensurePolled();
+        var d = a.display.shift,
+            e = !1;
+        try {
+            ua(a) && (a.state.suppressEdits = !0), c && (a.display.shift = !1), e = b(a) != Uf
+        } finally {
+            a.display.shift = d, a.state.suppressEdits = !1
+        }
+        return e
+    }
+
+    function Oc(a, b, c) {
+        for (var d = 0; d < a.state.keyMaps.length; d++) {
+            var e = Od(b, a.state.keyMaps[d], c, a);
+            if (e) return e
+        }
+        return a.options.extraKeys && Od(b, a.options.extraKeys, c, a) || Od(b, a.options.keyMap, c, a)
+    }
+
+    function Qc(a, b, c, d) {
+        var e = a.state.keySeq;
+        if (e) {
+            if (Pd(b)) return "handled";
+            Pc.set(50, function () {
+                a.state.keySeq == e && (a.state.keySeq = null, a.display.input.reset())
+            }), b = e + " " + b
+        }
+        var f = Oc(a, b, d);
+        return "multi" == f && (a.state.keySeq = b), "handled" == f && Nf(a, "keyHandled", a, b, c), ("handled" == f || "multi" == f) && (Df(c), hb(a)), e && !f && /\'$/.test(b) ? (Df(c), !0) : !!f
+    }
+
+    function Rc(a, b) {
+        var c = Qd(b, !0);
+        return c ? b.shiftKey && !a.state.keySeq ? Qc(a, "Shift-" + c, b, function (b) {
+            return Nc(a, b, !0)
+        }) || Qc(a, c, b, function (b) {
+            return ("string" == typeof b ? /^go[A-Z]/.test(b) : b.motion) ? Nc(a, b) : void 0
+        }) : Qc(a, c, b, function (b) {
+            return Nc(a, b)
+        }) : !1
+    }
+
+    function Sc(a, b, c) {
+        return Qc(a, "'" + c + "'", b, function (b) {
+            return Nc(a, b, !0)
+        })
+    }
+
+    function Uc(a) {
+        var b = this;
+        if (b.curOp.focus = ug(), !Pf(b, a)) {
+            d && 11 > e && 27 == a.keyCode && (a.returnValue = !1);
+            var c = a.keyCode;
+            b.display.shift = 16 == c || a.shiftKey;
+            var f = Rc(b, a);
+            i && (Tc = f ? c : null, !f && 88 == c && !Kg && (o ? a.metaKey : a.ctrlKey) && b.replaceSelection("", null, "cut")), 18 != c || /\bCodeMirror-crosshair\b/.test(b.display.lineDiv.className) || Vc(b)
+        }
+    }
+
+    function Vc(a) {
+        function c(a) {
+            18 != a.keyCode && a.altKey || (wg(b, "CodeMirror-crosshair"), Kf(document, "keyup", c), Kf(document, "mouseover", c))
+        }
+        var b = a.display.lineDiv;
+        xg(b, "CodeMirror-crosshair"), Jf(document, "keyup", c), Jf(document, "mouseover", c)
+    }
+
+    function Wc(a) {
+        16 == a.keyCode && (this.doc.sel.shift = !1), Pf(this, a)
+    }
+
+    function Xc(a) {
+        var b = this;
+        if (!(sc(b.display, a) || Pf(b, a) || a.ctrlKey && !a.altKey || o && a.metaKey)) {
+            var c = a.keyCode,
+                d = a.charCode;
+            if (i && c == Tc) return Tc = null, void Df(a);
+            if (!i || a.which && !(a.which < 10) || !Rc(b, a)) {
+                var e = String.fromCharCode(null == d ? c : d);
+                Sc(b, a, e) || b.display.input.onKeyPress(a)
+            }
+        }
+    }
+
+    function Yc(a) {
+        a.state.delayingBlurEvent = !0, setTimeout(function () {
+            a.state.delayingBlurEvent && (a.state.delayingBlurEvent = !1, $c(a))
+        }, 100)
+    }
+
+    function Zc(a) {
+        a.state.delayingBlurEvent && (a.state.delayingBlurEvent = !1), "nocursor" != a.options.readOnly && (a.state.focused || (Lf(a, "focus", a), a.state.focused = !0, xg(a.display.wrapper, "CodeMirror-focused"), a.curOp || a.display.selForContextMenu == a.doc.sel || (a.display.input.reset(), f && setTimeout(function () {
+            a.display.input.reset(!0)
+        }, 20)), a.display.input.receivedFocus()), hb(a))
+    }
+
+    function $c(a) {
+        a.state.delayingBlurEvent || (a.state.focused && (Lf(a, "blur", a), a.state.focused = !1, wg(a.display.wrapper, "CodeMirror-focused")), clearInterval(a.display.blinker), setTimeout(function () {
+            a.state.focused || (a.display.shift = !1)
+        }, 150))
+    }
+
+    function _c(a, b) {
+        sc(a.display, b) || ad(a, b) || a.display.input.onContextMenu(b)
+    }
+
+    function ad(a, b) {
+        return Rf(a, "gutterContextMenu") ? Ac(a, b, "gutterContextMenu", !1, Lf) : !1
+    }
+
+    function cd(a, b) {
+        if (pa(a, b.from) < 0) return a;
+        if (pa(a, b.to) <= 0) return bd(b);
+        var c = a.line + b.text.length - (b.to.line - b.from.line) - 1,
+            d = a.ch;
+        return a.line == b.to.line && (d += bd(b)
+            .ch - b.to.ch), oa(c, d)
+    }
+
+    function dd(a, b) {
+        for (var c = [], d = 0; d < a.sel.ranges.length; d++) {
+            var e = a.sel.ranges[d];
+            c.push(new Ka(cd(e.anchor, b), cd(e.head, b)))
+        }
+        return La(c, a.sel.primIndex)
+    }
+
+    function ed(a, b, c) {
+        return a.line == b.line ? oa(c.line, a.ch - b.ch + c.ch) : oa(c.line + (a.line - b.line), a.ch)
+    }
+
+    function fd(a, b, c) {
+        for (var d = [], e = oa(a.first, 0), f = e, g = 0; g < b.length; g++) {
+            var h = b[g],
+                i = ed(h.from, e, f),
+                j = ed(bd(h), e, f);
+            if (e = h.to, f = j, "around" == c) {
+                var k = a.sel.ranges[g],
+                    l = pa(k.head, k.anchor) < 0;
+                d[g] = new Ka(l ? j : i, l ? i : j)
+            } else d[g] = new Ka(i, i)
+        }
+        return new Ja(d, a.sel.primIndex)
+    }
+
+    function gd(a, b, c) {
+        var d = {
+            canceled: !1,
+            from: b.from,
+            to: b.to,
+            text: b.text,
+            origin: b.origin,
+            cancel: function () {
+                this.canceled = !0
+            }
+        };
+        return c && (d.update = function (b, c, d, e) {
+            b && (this.from = Oa(a, b)), c && (this.to = Oa(a, c)), d && (this.text = d), void 0 !== e && (this.origin = e)
+        }), Lf(a, "beforeChange", a, d), a.cm && Lf(a.cm, "beforeChange", a.cm, d), d.canceled ? null : {
+            from: d.from,
+            to: d.to,
+            text: d.text,
+            origin: d.origin
+        }
+    }
+
+    function hd(a, b, c) {
+        if (a.cm) {
+            if (!a.cm.curOp) return dc(a.cm, hd)(a, b, c);
+            if (a.cm.state.suppressEdits) return
+        }
+        if (!(Rf(a, "beforeChange") || a.cm && Rf(a.cm, "beforeChange")) || (b = gd(a, b, !0))) {
+            var d = t && !c && ie(a, b.from, b.to);
+            if (d)
+                for (var e = d.length - 1; e >= 0; --e) id(a, {
+                    from: d[e].from,
+                    to: d[e].to,
+                    text: e ? [""] : b.text
+                });
+            else id(a, b)
+        }
+    }
+
+    function id(a, b) {
+        if (1 != b.text.length || "" != b.text[0] || 0 != pa(b.from, b.to)) {
+            var c = dd(a, b);
+            sf(a, b, c, a.cm ? a.cm.curOp.id : NaN), ld(a, b, c, fe(a, b));
+            var d = [];
+            df(a, function (a, c) {
+                c || -1 != dg(d, a.history) || (Cf(a.history, b), d.push(a.history)), ld(a, b, null, fe(a, b))
+            })
+        }
+    }
+
+    function jd(a, b, c) {
+        if (!a.cm || !a.cm.state.suppressEdits) {
+            for (var e, d = a.history, f = a.sel, g = "undo" == b ? d.done : d.undone, h = "undo" == b ? d.undone : d.done, i = 0; i < g.length && (e = g[i], c ? !e.ranges || e.equals(a.sel) : e.ranges); i++);
+            if (i != g.length) {
+                for (d.lastOrigin = d.lastSelOrigin = null; e = g.pop(), e.ranges;) {
+                    if (vf(e, h), c && !e.equals(a.sel)) return void Za(a, e, {
+                        clearRedo: !1
+                    });
+                    f = e
+                }
+                var j = [];
+                vf(f, h), h.push({
+                    changes: j,
+                    generation: d.generation
+                }), d.generation = e.generation || ++d.maxGeneration;
+                for (var k = Rf(a, "beforeChange") || a.cm && Rf(a.cm, "beforeChange"), i = e.changes.length - 1; i >= 0; --i) {
+                    var l = e.changes[i];
+                    if (l.origin = b, k && !gd(a, l, !1)) return void(g.length = 0);
+                    j.push(pf(a, l));
+                    var m = i ? dd(a, l) : bg(g);
+                    ld(a, l, m, he(a, l)), !i && a.cm && a.cm.scrollIntoView({
+                        from: l.from,
+                        to: bd(l)
+                    });
+                    var n = [];
+                    df(a, function (a, b) {
+                        b || -1 != dg(n, a.history) || (Cf(a.history, l), n.push(a.history)), ld(a, l, null, he(a, l))
+                    })
+                }
+            }
+        }
+    }
+
+    function kd(a, b) {
+        if (0 != b && (a.first += b, a.sel = new Ja(eg(a.sel.ranges, function (a) {
+                return new Ka(oa(a.anchor.line + b, a.anchor.ch), oa(a.head.line + b, a.head.ch))
+            }), a.sel.primIndex), a.cm)) {
+            ic(a.cm, a.first, a.first - b, b);
+            for (var c = a.cm.display, d = c.viewFrom; d < c.viewTo; d++) jc(a.cm, d, "gutter")
+        }
+    }
+
+    function ld(a, b, c, d) {
+        if (a.cm && !a.cm.curOp) return dc(a.cm, ld)(a, b, c, d);
+        if (b.to.line < a.first) return void kd(a, b.text.length - 1 - (b.to.line - b.from.line));
+        if (!(b.from.line > a.lastLine())) {
+            if (b.from.line < a.first) {
+                var e = b.text.length - 1 - (a.first - b.from.line);
+                kd(a, e), b = {
+                    from: oa(a.first, 0),
+                    to: oa(b.to.line + e, b.to.ch),
+                    text: [bg(b.text)],
+                    origin: b.origin
+                }
+            }
+            var f = a.lastLine();
+            b.to.line > f && (b = {
+                from: b.from,
+                to: oa(f, ff(a, f)
+                    .text.length),
+                text: [b.text[0]],
+                origin: b.origin
+            }), b.removed = gf(a, b.from, b.to), c || (c = dd(a, b)), a.cm ? md(a.cm, b, d) : Ye(a, b, d), $a(a, c, Vf)
+        }
+    }
+
+    function md(a, b, c) {
+        var d = a.doc,
+            e = a.display,
+            f = b.from,
+            g = b.to,
+            h = !1,
+            i = f.line;
+        a.options.lineWrapping || (i = kf(se(ff(d, f.line))), d.iter(i, g.line + 1, function (a) {
+            return a == e.maxLine ? (h = !0, !0) : void 0
+        })), d.sel.contains(b.from, b.to) > -1 && Qf(a), Ye(d, b, c, A(a)), a.options.lineWrapping || (d.iter(i, f.line + b.text.length, function (a) {
+            var b = G(a);
+            b > e.maxLineLength && (e.maxLine = a, e.maxLineLength = b, e.maxLineChanged = !0, h = !1)
+        }), h && (a.curOp.updateMaxLine = !0)), d.frontier = Math.min(d.frontier, f.line), ib(a, 400);
+        var j = b.text.length - (g.line - f.line) - 1;
+        b.full ? ic(a) : f.line != g.line || 1 != b.text.length || Xe(a.doc, b) ? ic(a, f.line, g.line + 1, j) : jc(a, f.line, "text");
+        var k = Rf(a, "changes"),
+            l = Rf(a, "change");
+        if (l || k) {
+            var m = {
+                from: f,
+                to: g,
+                text: b.text,
+                removed: b.removed,
+                origin: b.origin
+            };
+            l && Nf(a, "change", a, m), k && (a.curOp.changeObjs || (a.curOp.changeObjs = []))
+                .push(m)
+        }
+        a.display.selForContextMenu = null
+    }
+
+    function nd(a, b, c, d, e) {
+        if (d || (d = c), pa(d, c) < 0) {
+            var f = d;
+            d = c, c = f
+        }
+        "string" == typeof b && (b = a.splitLines(b)), hd(a, {
+            from: c,
+            to: d,
+            text: b,
+            origin: e
+        })
+    }
+
+    function od(a, b) {
+        if (!Pf(a, "scrollCursorIntoView")) {
+            var c = a.display,
+                d = c.sizer.getBoundingClientRect(),
+                e = null;
+            if (b.top + d.top < 0 ? e = !0 : b.bottom + d.top > (window.innerHeight || document.documentElement.clientHeight) && (e = !1), null != e && !l) {
+                var f = pg("div", "\u200b", null, "position: absolute; top: " + (b.top - c.viewOffset - mb(a.display)) + "px; height: " + (b.bottom - b.top + pb(a) + c.barHeight) + "px; left: " + b.left + "px; width: 2px;");
+                a.display.lineSpace.appendChild(f), f.scrollIntoView(e), a.display.lineSpace.removeChild(f)
+            }
+        }
+    }
+
+    function pd(a, b, c, d) {
+        null == d && (d = 0);
+        for (var e = 0; 5 > e; e++) {
+            var f = !1,
+                g = Lb(a, b),
+                h = c && c != b ? Lb(a, c) : g,
+                i = rd(a, Math.min(g.left, h.left), Math.min(g.top, h.top) - d, Math.max(g.left, h.left), Math.max(g.bottom, h.bottom) + d),
+                j = a.doc.scrollTop,
+                k = a.doc.scrollLeft;
+            if (null != i.scrollTop && (Hc(a, i.scrollTop), Math.abs(a.doc.scrollTop - j) > 1 && (f = !0)), null != i.scrollLeft && (Ic(a, i.scrollLeft), Math.abs(a.doc.scrollLeft - k) > 1 && (f = !0)), !f) break
+        }
+        return g
+    }
+
+    function qd(a, b, c, d, e) {
+        var f = rd(a, b, c, d, e);
+        null != f.scrollTop && Hc(a, f.scrollTop), null != f.scrollLeft && Ic(a, f.scrollLeft)
+    }
+
+    function rd(a, b, c, d, e) {
+        var f = a.display,
+            g = Rb(a.display);
+        0 > c && (c = 0);
+        var h = a.curOp && null != a.curOp.scrollTop ? a.curOp.scrollTop : f.scroller.scrollTop,
+            i = rb(a),
+            j = {};
+        e - c > i && (e = c + i);
+        var k = a.doc.height + nb(f),
+            l = g > c,
+            m = e > k - g;
+        if (h > c) j.scrollTop = l ? 0 : c;
+        else if (e > h + i) {
+            var n = Math.min(c, (m ? k : e) - i);
+            n != h && (j.scrollTop = n)
+        }
+        var o = a.curOp && null != a.curOp.scrollLeft ? a.curOp.scrollLeft : f.scroller.scrollLeft,
+            p = qb(a) - (a.options.fixedGutter ? f.gutters.offsetWidth : 0),
+            q = d - b > p;
+        return q && (d = b + p), 10 > b ? j.scrollLeft = 0 : o > b ? j.scrollLeft = Math.max(0, b - (q ? 0 : 10)) : d > p + o - 3 && (j.scrollLeft = d + (q ? 0 : 10) - p), j
+    }
+
+    function sd(a, b, c) {
+        (null != b || null != c) && ud(a), null != b && (a.curOp.scrollLeft = (null == a.curOp.scrollLeft ? a.doc.scrollLeft : a.curOp.scrollLeft) + b), null != c && (a.curOp.scrollTop = (null == a.curOp.scrollTop ? a.doc.scrollTop : a.curOp.scrollTop) + c)
+    }
+
+    function td(a) {
+        ud(a);
+        var b = a.getCursor(),
+            c = b,
+            d = b;
+        a.options.lineWrapping || (c = b.ch ? oa(b.line, b.ch - 1) : b, d = oa(b.line, b.ch + 1)), a.curOp.scrollToPos = {
+            from: c,
+            to: d,
+            margin: a.options.cursorScrollMargin,
+            isCursor: !0
+        }
+    }
+
+    function ud(a) {
+        var b = a.curOp.scrollToPos;
+        if (b) {
+            a.curOp.scrollToPos = null;
+            var c = Mb(a, b.from),
+                d = Mb(a, b.to),
+                e = rd(a, Math.min(c.left, d.left), Math.min(c.top, d.top) - b.margin, Math.max(c.right, d.right), Math.max(c.bottom, d.bottom) + b.margin);
+            a.scrollTo(e.scrollLeft, e.scrollTop)
+        }
+    }
+
+    function vd(a, b, c, d) {
+        var f, e = a.doc;
+        null == c && (c = "add"), "smart" == c && (e.mode.indent ? f = lb(a, b) : c = "prev");
+        var g = a.options.tabSize,
+            h = ff(e, b),
+            i = Zf(h.text, null, g);
+        h.stateAfter && (h.stateAfter = null);
+        var k, j = h.text.match(/^\s*/)[0];
+        if (d || /\S/.test(h.text)) {
+            if ("smart" == c && (k = e.mode.indent(f, h.text.slice(j.length), h.text), k == Uf || k > 150)) {
+                if (!d) return;
+                c = "prev"
+            }
+        } else k = 0, c = "not";
+        "prev" == c ? k = b > e.first ? Zf(ff(e, b - 1)
+            .text, null, g) : 0 : "add" == c ? k = i + a.options.indentUnit : "subtract" == c ? k = i - a.options.indentUnit : "number" == typeof c && (k = i + c), k = Math.max(0, k);
+        var l = "",
+            m = 0;
+        if (a.options.indentWithTabs)
+            for (var n = Math.floor(k / g); n; --n) m += g, l += "	";
+        if (k > m && (l += ag(k - m)), l != j) return nd(e, l, oa(b, 0), oa(b, j.length), "+input"), h.stateAfter = null, !0;
+        for (var n = 0; n < e.sel.ranges.length; n++) {
+            var o = e.sel.ranges[n];
+            if (o.head.line == b && o.head.ch < j.length) {
+                var m = oa(b, j.length);
+                Va(e, n, new Ka(m, m));
+                break
+            }
+        }
+    }
+
+    function wd(a, b, c, d) {
+        var e = b,
+            f = b;
+        return "number" == typeof b ? f = ff(a, Na(a, b)) : e = kf(b), null == e ? null : (d(f, e) && a.cm && jc(a.cm, e, c), f)
+    }
+
+    function xd(a, b) {
+        for (var c = a.doc.sel.ranges, d = [], e = 0; e < c.length; e++) {
+            for (var f = b(c[e]); d.length && pa(f.from, bg(d)
+                    .to) <= 0;) {
+                var g = d.pop();
+                if (pa(g.from, f.from) < 0) {
+                    f.from = g.from;
+                    break
+                }
+            }
+            d.push(f)
+        }
+        cc(a, function () {
+            for (var b = d.length - 1; b >= 0; b--) nd(a.doc, "", d[b].from, d[b].to, "+delete");
+            td(a)
+        })
+    }
+
+    function yd(a, b, c, d, e) {
+        function k() {
+            var b = f + c;
+            return b < a.first || b >= a.first + a.size ? j = !1 : (f = b, i = ff(a, b))
+        }
+
+        function l(a) {
+            var b = (e ? $g : _g)(i, g, c, !0);
+            if (null == b) {
+                if (a || !k()) return j = !1;
+                g = e ? (0 > c ? Sg : Rg)(i) : 0 > c ? i.text.length : 0
+            } else g = b;
+            return !0
+        }
+        var f = b.line,
+            g = b.ch,
+            h = c,
+            i = ff(a, f),
+            j = !0;
+        if ("char" == d) l();
+        else if ("column" == d) l(!0);
+        else if ("word" == d || "group" == d)
+            for (var m = null, n = "group" == d, o = a.cm && a.cm.getHelper(b, "wordChars"), p = !0; !(0 > c) || l(!p); p = !1) {
+                var q = i.text.charAt(g) || "\n",
+                    r = lg(q, o) ? "w" : n && "\n" == q ? "n" : !n || /\s/.test(q) ? null : "p";
+                if (!n || p || r || (r = "s"), m && m != r) {
+                    0 > c && (c = 1, l());
+                    break
+                }
+                if (r && (m = r), c > 0 && !l(!p)) break
+            }
+        var s = cb(a, oa(f, g), h, !0);
+        return j || (s.hitSide = !0), s
+    }
+
+    function zd(a, b, c, d) {
+        var g, e = a.doc,
+            f = b.left;
+        if ("page" == d) {
+            var h = Math.min(a.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
+            g = b.top + c * (h - (0 > c ? 1.5 : .5) * Rb(a.display))
+        } else "line" == d && (g = c > 0 ? b.bottom + 3 : b.top - 3);
+        for (;;) {
+            var i = Ob(a, f, g);
+            if (!i.outside) break;
+            if (0 > c ? 0 >= g : g >= e.height) {
+                i.hitSide = !0;
+                break
+            }
+            g += 5 * c
+        }
+        return i
+    }
+
+    function Cd(a, b, c, d) {
+        v.defaults[a] = b, c && (Bd[a] = d ? function (a, b, d) {
+            d != Dd && c(a, b, d)
+        } : c)
+    }
+
+    function Nd(a) {
+        for (var c, d, e, f, b = a.split(/-(?!$)/), a = b[b.length - 1], g = 0; g < b.length - 1; g++) {
+            var h = b[g];
+            if (/^(cmd|meta|m)$/i.test(h)) f = !0;
+            else if (/^a(lt)?$/i.test(h)) c = !0;
+            else if (/^(c|ctrl|control)$/i.test(h)) d = !0;
+            else {
+                if (!/^s(hift)$/i.test(h)) throw new Error("Unrecognized modifier name: " + h);
+                e = !0
+            }
+        }
+        return c && (a = "Alt-" + a), d && (a = "Ctrl-" + a), f && (a = "Cmd-" + a), e && (a = "Shift-" + a), a
+    }
+
+    function Rd(a) {
+        return "string" == typeof a ? Md[a] : a
+    }
+
+    function Vd(a, b, c, d, e) {
+        if (d && d.shared) return Xd(a, b, c, d, e);
+        if (a.cm && !a.cm.curOp) return dc(a.cm, Vd)(a, b, c, d, e);
+        var f = new Ud(a, e),
+            g = pa(b, c);
+        if (d && hg(d, f, !1), g > 0 || 0 == g && f.clearWhenEmpty !== !1) return f;
+        if (f.replacedWith && (f.collapsed = !0, f.widgetNode = pg("span", [f.replacedWith], "CodeMirror-widget"), d.handleMouseEvents || f.widgetNode.setAttribute("cm-ignore-events", "true"), d.insertLeft && (f.widgetNode.insertLeft = !0)), f.collapsed) {
+            if (re(a, b.line, b, c, f) || b.line != c.line && re(a, c.line, b, c, f)) throw new Error("Inserting collapsed marker partially overlapping an existing one");
+            u = !0
+        }
+        f.addToHistory && sf(a, {
+            from: b,
+            to: c,
+            origin: "markText"
+        }, a.sel, NaN);
+        var j, h = b.line,
+            i = a.cm;
+        if (a.iter(h, c.line + 1, function (a) {
+                i && f.collapsed && !i.options.lineWrapping && se(a) == i.display.maxLine && (j = !0), f.collapsed && h != b.line && jf(a, 0), ce(a, new _d(f, h == b.line ? b.ch : null, h == c.line ? c.ch : null)), ++h
+            }), f.collapsed && a.iter(b.line, c.line + 1, function (b) {
+                we(a, b) && jf(b, 0)
+            }), f.clearOnEnter && Jf(f, "beforeCursorEnter", function () {
+                f.clear()
+            }), f.readOnly && (t = !0, (a.history.done.length || a.history.undone.length) && a.clearHistory()), f.collapsed && (f.id = ++Td, f.atomic = !0), i) {
+            if (j && (i.curOp.updateMaxLine = !0), f.collapsed) ic(i, b.line, c.line + 1);
+            else if (f.className || f.title || f.startStyle || f.endStyle || f.css)
+                for (var k = b.line; k <= c.line; k++) jc(i, k, "text");
+            f.atomic && ab(i.doc), Nf(i, "markerAdded", i, f)
+        }
+        return f
+    }
+
+    function Xd(a, b, c, d, e) {
+        d = hg(d), d.shared = !1;
+        var f = [Vd(a, b, c, d, e)],
+            g = f[0],
+            h = d.widgetNode;
+        return df(a, function (a) {
+            h && (d.widgetNode = h.cloneNode(!0)), f.push(Vd(a, Oa(a, b), Oa(a, c), d, e));
+            for (var i = 0; i < a.linked.length; ++i)
+                if (a.linked[i].isParent) return;
+            g = bg(f)
+        }), new Wd(f, g)
+    }
+
+    function Yd(a) {
+        return a.findMarks(oa(a.first, 0), a.clipPos(oa(a.lastLine())), function (a) {
+            return a.parent
+        })
+    }
+
+    function Zd(a, b) {
+        for (var c = 0; c < b.length; c++) {
+            var d = b[c],
+                e = d.find(),
+                f = a.clipPos(e.from),
+                g = a.clipPos(e.to);
+            if (pa(f, g)) {
+                var h = Vd(a, f, g, d.primary, d.primary.type);
+                d.markers.push(h), h.parent = d
+            }
+        }
+    }
+
+    function $d(a) {
+        for (var b = 0; b < a.length; b++) {
+            var c = a[b],
+                d = [c.primary.doc];
+            df(c.primary.doc, function (a) {
+                d.push(a)
+            });
+            for (var e = 0; e < c.markers.length; e++) {
+                var f = c.markers[e]; - 1 == dg(d, f.doc) && (f.parent = null, c.markers.splice(e--, 1))
+            }
+        }
+    }
+
+    function _d(a, b, c) {
+        this.marker = a, this.from = b, this.to = c
+    }
+
+    function ae(a, b) {
+        if (a)
+            for (var c = 0; c < a.length; ++c) {
+                var d = a[c];
+                if (d.marker == b) return d
+            }
+    }
+
+    function be(a, b) {
+        for (var c, d = 0; d < a.length; ++d) a[d] != b && (c || (c = []))
+            .push(a[d]);
+        return c
+    }
+
+    function ce(a, b) {
+        a.markedSpans = a.markedSpans ? a.markedSpans.concat([b]) : [b], b.marker.attachLine(a)
+    }
+
+    function de(a, b, c) {
+        if (a)
+            for (var e, d = 0; d < a.length; ++d) {
+                var f = a[d],
+                    g = f.marker,
+                    h = null == f.from || (g.inclusiveLeft ? f.from <= b : f.from < b);
+                if (h || f.from == b && "bookmark" == g.type && (!c || !f.marker.insertLeft)) {
+                    var i = null == f.to || (g.inclusiveRight ? f.to >= b : f.to > b);
+                    (e || (e = []))
+                    .push(new _d(g, f.from, i ? null : f.to))
+                }
+            }
+        return e
+    }
+
+    function ee(a, b, c) {
+        if (a)
+            for (var e, d = 0; d < a.length; ++d) {
+                var f = a[d],
+                    g = f.marker,
+                    h = null == f.to || (g.inclusiveRight ? f.to >= b : f.to > b);
+                if (h || f.from == b && "bookmark" == g.type && (!c || f.marker.insertLeft)) {
+                    var i = null == f.from || (g.inclusiveLeft ? f.from <= b : f.from < b);
+                    (e || (e = []))
+                    .push(new _d(g, i ? null : f.from - b, null == f.to ? null : f.to - b))
+                }
+            }
+        return e
+    }
+
+    function fe(a, b) {
+        if (b.full) return null;
+        var c = Qa(a, b.from.line) && ff(a, b.from.line)
+            .markedSpans,
+            d = Qa(a, b.to.line) && ff(a, b.to.line)
+            .markedSpans;
+        if (!c && !d) return null;
+        var e = b.from.ch,
+            f = b.to.ch,
+            g = 0 == pa(b.from, b.to),
+            h = de(c, e, g),
+            i = ee(d, f, g),
+            j = 1 == b.text.length,
+            k = bg(b.text)
+            .length + (j ? e : 0);
+        if (h)
+            for (var l = 0; l < h.length; ++l) {
+                var m = h[l];
+                if (null == m.to) {
+                    var n = ae(i, m.marker);
+                    n ? j && (m.to = null == n.to ? null : n.to + k) : m.to = e
+                }
+            }
+        if (i)
+            for (var l = 0; l < i.length; ++l) {
+                var m = i[l];
+                if (null != m.to && (m.to += k), null == m.from) {
+                    var n = ae(h, m.marker);
+                    n || (m.from = k, j && (h || (h = []))
+                        .push(m))
+                } else m.from += k, j && (h || (h = []))
+                    .push(m)
+            }
+        h && (h = ge(h)), i && i != h && (i = ge(i));
+        var o = [h];
+        if (!j) {
+            var q, p = b.text.length - 2;
+            if (p > 0 && h)
+                for (var l = 0; l < h.length; ++l) null == h[l].to && (q || (q = []))
+                    .push(new _d(h[l].marker, null, null));
+            for (var l = 0; p > l; ++l) o.push(q);
+            o.push(i)
+        }
+        return o
+    }
+
+    function ge(a) {
+        for (var b = 0; b < a.length; ++b) {
+            var c = a[b];
+            null != c.from && c.from == c.to && c.marker.clearWhenEmpty !== !1 && a.splice(b--, 1)
+        }
+        return a.length ? a : null
+    }
+
+    function he(a, b) {
+        var c = yf(a, b),
+            d = fe(a, b);
+        if (!c) return d;
+        if (!d) return c;
+        for (var e = 0; e < c.length; ++e) {
+            var f = c[e],
+                g = d[e];
+            if (f && g) a: for (var h = 0; h < g.length; ++h) {
+                for (var i = g[h], j = 0; j < f.length; ++j)
+                    if (f[j].marker == i.marker) continue a;
+                f.push(i)
+            } else g && (c[e] = g)
+        }
+        return c
+    }
+
+    function ie(a, b, c) {
+        var d = null;
+        if (a.iter(b.line, c.line + 1, function (a) {
+                if (a.markedSpans)
+                    for (var b = 0; b < a.markedSpans.length; ++b) {
+                        var c = a.markedSpans[b].marker;
+                        !c.readOnly || d && -1 != dg(d, c) || (d || (d = []))
+                            .push(c)
+                    }
+            }), !d) return null;
+        for (var e = [{
+                from: b,
+                to: c
+            }], f = 0; f < d.length; ++f)
+            for (var g = d[f], h = g.find(0), i = 0; i < e.length; ++i) {
+                var j = e[i];
+                if (!(pa(j.to, h.from) < 0 || pa(j.from, h.to) > 0)) {
+                    var k = [i, 1],
+                        l = pa(j.from, h.from),
+                        m = pa(j.to, h.to);
+                    (0 > l || !g.inclusiveLeft && !l) && k.push({
+                        from: j.from,
+                        to: h.from
+                    }), (m > 0 || !g.inclusiveRight && !m) && k.push({
+                        from: h.to,
+                        to: j.to
+                    }), e.splice.apply(e, k), i += k.length - 1
+                }
+            }
+        return e
+    }
+
+    function je(a) {
+        var b = a.markedSpans;
+        if (b) {
+            for (var c = 0; c < b.length; ++c) b[c].marker.detachLine(a);
+            a.markedSpans = null
+        }
+    }
+
+    function ke(a, b) {
+        if (b) {
+            for (var c = 0; c < b.length; ++c) b[c].marker.attachLine(a);
+            a.markedSpans = b
+        }
+    }
+
+    function le(a) {
+        return a.inclusiveLeft ? -1 : 0
+    }
+
+    function me(a) {
+        return a.inclusiveRight ? 1 : 0
+    }
+
+    function ne(a, b) {
+        var c = a.lines.length - b.lines.length;
+        if (0 != c) return c;
+        var d = a.find(),
+            e = b.find(),
+            f = pa(d.from, e.from) || le(a) - le(b);
+        if (f) return -f;
+        var g = pa(d.to, e.to) || me(a) - me(b);
+        return g ? g : b.id - a.id
+    }
+
+    function oe(a, b) {
+        var d, c = u && a.markedSpans;
+        if (c)
+            for (var e, f = 0; f < c.length; ++f) e = c[f], e.marker.collapsed && null == (b ? e.from : e.to) && (!d || ne(d, e.marker) < 0) && (d = e.marker);
+        return d
+    }
+
+    function pe(a) {
+        return oe(a, !0)
+    }
+
+    function qe(a) {
+        return oe(a, !1)
+    }
+
+    function re(a, b, c, d, e) {
+        var f = ff(a, b),
+            g = u && f.markedSpans;
+        if (g)
+            for (var h = 0; h < g.length; ++h) {
+                var i = g[h];
+                if (i.marker.collapsed) {
+                    var j = i.marker.find(0),
+                        k = pa(j.from, c) || le(i.marker) - le(e),
+                        l = pa(j.to, d) || me(i.marker) - me(e);
+                    if (!(k >= 0 && 0 >= l || 0 >= k && l >= 0) && (0 >= k && (pa(j.to, c) > 0 || i.marker.inclusiveRight && e.inclusiveLeft) || k >= 0 && (pa(j.from, d) < 0 || i.marker.inclusiveLeft && e.inclusiveRight))) return !0
+                }
+            }
+    }
+
+    function se(a) {
+        for (var b; b = pe(a);) a = b.find(-1, !0)
+            .line;
+        return a
+    }
+
+    function te(a) {
+        for (var b, c; b = qe(a);) a = b.find(1, !0)
+            .line, (c || (c = []))
+            .push(a);
+        return c
+    }
+
+    function ue(a, b) {
+        var c = ff(a, b),
+            d = se(c);
+        return c == d ? b : kf(d)
+    }
+
+    function ve(a, b) {
+        if (b > a.lastLine()) return b;
+        var d, c = ff(a, b);
+        if (!we(a, c)) return b;
+        for (; d = qe(c);) c = d.find(1, !0)
+            .line;
+        return kf(c) + 1
+    }
+
+    function we(a, b) {
+        var c = u && b.markedSpans;
+        if (c)
+            for (var d, e = 0; e < c.length; ++e)
+                if (d = c[e], d.marker.collapsed) {
+                    if (null == d.from) return !0;
+                    if (!d.marker.widgetNode && 0 == d.from && d.marker.inclusiveLeft && xe(a, b, d)) return !0
+                }
+    }
+
+    function xe(a, b, c) {
+        if (null == c.to) {
+            var d = c.marker.find(1, !0);
+            return xe(a, d.line, ae(d.line.markedSpans, c.marker))
+        }
+        if (c.marker.inclusiveRight && c.to == b.text.length) return !0;
+        for (var e, f = 0; f < b.markedSpans.length; ++f)
+            if (e = b.markedSpans[f], e.marker.collapsed && !e.marker.widgetNode && e.from == c.to && (null == e.to || e.to != c.from) && (e.marker.inclusiveLeft || c.marker.inclusiveRight) && xe(a, b, e)) return !0
+    }
+
+    function ze(a, b, c) {
+        mf(b) < (a.curOp && a.curOp.scrollTop || a.doc.scrollTop) && sd(a, null, c)
+    }
+
+    function Ae(a) {
+        if (null != a.height) return a.height;
+        var b = a.doc.cm;
+        if (!b) return 0;
+        if (!tg(document.body, a.node)) {
+            var c = "position: relative;";
+            a.coverGutter && (c += "margin-left: -" + b.display.gutters.offsetWidth + "px;"), a.noHScroll && (c += "width: " + b.display.wrapper.clientWidth + "px;"), sg(b.display.measure, pg("div", [a.node], null, c))
+        }
+        return a.height = a.node.offsetHeight
+    }
+
+    function Be(a, b, c, d) {
+        var e = new ye(a, c, d),
+            f = a.cm;
+        return f && e.noHScroll && (f.display.alignWidgets = !0), wd(a, b, "widget", function (b) {
+            var c = b.widgets || (b.widgets = []);
+            if (null == e.insertAt ? c.push(e) : c.splice(Math.min(c.length - 1, Math.max(0, e.insertAt)), 0, e), e.line = b, f && !we(a, b)) {
+                var d = mf(b) < a.scrollTop;
+                jf(b, b.height + Ae(e)), d && sd(f, null, e.height), f.curOp.forceUpdate = !0
+            }
+            return !0
+        }), e
+    }
+
+    function De(a, b, c, d) {
+        a.text = b, a.stateAfter && (a.stateAfter = null), a.styles && (a.styles = null), null != a.order && (a.order = null), je(a), ke(a, c);
+        var e = d ? d(a) : 1;
+        e != a.height && jf(a, e)
+    }
+
+    function Ee(a) {
+        a.parent = null, je(a)
+    }
+
+    function Fe(a, b) {
+        if (a)
+            for (;;) {
+                var c = a.match(/(?:^|\s+)line-(background-)?(\S+)/);
+                if (!c) break;
+                a = a.slice(0, c.index) + a.slice(c.index + c[0].length);
+                var d = c[1] ? "bgClass" : "textClass";
+                null == b[d] ? b[d] = c[2] : new RegExp("(?:^|s)" + c[2] + "(?:$|s)")
+                    .test(b[d]) || (b[d] += " " + c[2])
+            }
+        return a
+    }
+
+    function Ge(a, b) {
+        if (a.blankLine) return a.blankLine(b);
+        if (a.innerMode) {
+            var c = v.innerMode(a, b);
+            return c.mode.blankLine ? c.mode.blankLine(c.state) : void 0
+        }
+    }
+
+    function He(a, b, c, d) {
+        for (var e = 0; 10 > e; e++) {
+            d && (d[0] = v.innerMode(a, c)
+                .mode);
+            var f = a.token(b, c);
+            if (b.pos > b.start) return f
+        }
+        throw new Error("Mode " + a.name + " failed to advance stream.")
+    }
+
+    function Ie(a, b, c, d) {
+        function e(a) {
+            return {
+                start: k.start,
+                end: k.pos,
+                string: k.current(),
+                type: h || null,
+                state: a ? Jd(f.mode, j) : j
+            }
+        }
+        var h, f = a.doc,
+            g = f.mode;
+        b = Oa(f, b);
+        var l, i = ff(f, b.line),
+            j = lb(a, b.line, c),
+            k = new Sd(i.text, a.options.tabSize);
+        for (d && (l = []);
+            (d || k.pos < b.ch) && !k.eol();) k.start = k.pos, h = He(g, k, j), d && l.push(e(!0));
+        return d ? l : e()
+    }
+
+    function Je(a, b, c, d, e, f, g) {
+        var h = c.flattenSpans;
+        null == h && (h = a.options.flattenSpans);
+        var l, i = 0,
+            j = null,
+            k = new Sd(b, a.options.tabSize),
+            m = a.options.addModeClass && [null];
+        for ("" == b && Fe(Ge(c, d), f); !k.eol();) {
+            if (k.pos > a.options.maxHighlightLength ? (h = !1, g && Me(a, b, d, k.pos), k.pos = b.length, l = null) : l = Fe(He(c, k, d, m), f), m) {
+                var n = m[0].name;
+                n && (l = "m-" + (l ? n + " " + l : n))
+            }
+            if (!h || j != l) {
+                for (; i < k.start;) i = Math.min(k.start, i + 5e4), e(i, j);
+                j = l
+            }
+            k.start = k.pos
+        }
+        for (; i < k.pos;) {
+            var o = Math.min(k.pos, i + 5e4);
+            e(o, j), i = o
+        }
+    }
+
+    function Ke(a, b, c, d) {
+        var e = [a.state.modeGen],
+            f = {};
+        Je(a, b.text, a.doc.mode, c, function (a, b) {
+            e.push(a, b)
+        }, f, d);
+        for (var g = 0; g < a.state.overlays.length; ++g) {
+            var h = a.state.overlays[g],
+                i = 1,
+                j = 0;
+            Je(a, b.text, h.mode, !0, function (a, b) {
+                for (var c = i; a > j;) {
+                    var d = e[i];
+                    d > a && e.splice(i, 1, a, e[i + 1], d), i += 2, j = Math.min(a, d)
+                }
+                if (b)
+                    if (h.opaque) e.splice(c, i - c, a, "cm-overlay " + b), i = c + 2;
+                    else
+                        for (; i > c; c += 2) {
+                            var f = e[c + 1];
+                            e[c + 1] = (f ? f + " " : "") + "cm-overlay " + b
+                        }
+            }, f)
+        }
+        return {
+            styles: e,
+            classes: f.bgClass || f.textClass ? f : null
+        }
+    }
+
+    function Le(a, b, c) {
+        if (!b.styles || b.styles[0] != a.state.modeGen) {
+            var d = lb(a, kf(b)),
+                e = Ke(a, b, b.text.length > a.options.maxHighlightLength ? Jd(a.doc.mode, d) : d);
+            b.stateAfter = d, b.styles = e.styles, e.classes ? b.styleClasses = e.classes : b.styleClasses && (b.styleClasses = null), c === a.doc.frontier && a.doc.frontier++
+        }
+        return b.styles
+    }
+
+    function Me(a, b, c, d) {
+        var e = a.doc.mode,
+            f = new Sd(b, a.options.tabSize);
+        for (f.start = f.pos = d || 0, "" == b && Ge(e, c); !f.eol();) He(e, f, c), f.start = f.pos
+    }
+
+    function Pe(a, b) {
+        if (!a || /^\s*$/.test(a)) return null;
+        var c = b.addModeClass ? Oe : Ne;
+        return c[a] || (c[a] = a.replace(/\S+/g, "cm-$&"))
+    }
+
+    function Qe(a, b) {
+        var c = pg("span", null, null, f ? "padding-right: .1px" : null),
+            e = {
+                pre: pg("pre", [c], "CodeMirror-line"),
+                content: c,
+                col: 0,
+                pos: 0,
+                cm: a,
+                splitSpaces: (d || f) && a.getOption("lineWrapping")
+            };
+        b.measure = {};
+        for (var g = 0; g <= (b.rest ? b.rest.length : 0); g++) {
+            var i, h = g ? b.rest[g - 1] : b.line;
+            e.pos = 0, e.addToken = Se, Hg(a.display.measure) && (i = nf(h)) && (e.addToken = Ue(e.addToken, i)), e.map = [];
+            var j = b != a.display.externalMeasured && kf(h);
+            We(h, e, Le(a, h, j)), h.styleClasses && (h.styleClasses.bgClass && (e.bgClass = yg(h.styleClasses.bgClass, e.bgClass || "")), h.styleClasses.textClass && (e.textClass = yg(h.styleClasses.textClass, e.textClass || ""))), 0 == e.map.length && e.map.push(0, 0, e.content.appendChild(Fg(a.display.measure))), 0 == g ? (b.measure.map = e.map, b.measure.cache = {}) : ((b.measure.maps || (b.measure.maps = []))
+                .push(e.map), (b.measure.caches || (b.measure.caches = []))
+                .push({}))
+        }
+        return f && /\bcm-tab\b/.test(e.content.lastChild.className) && (e.content.className = "cm-tab-wrap-hack"), Lf(a, "renderLine", a, b.line, e.pre), e.pre.className && (e.textClass = yg(e.pre.className, e.textClass || "")), e
+    }
+
+    function Re(a) {
+        var b = pg("span", "\u2022", "cm-invalidchar");
+        return b.title = "\\u" + a.charCodeAt(0)
+            .toString(16), b.setAttribute("aria-label", b.title), b
+    }
+
+    function Se(a, b, c, f, g, h, i) {
+        if (b) {
+            var j = a.splitSpaces ? b.replace(/ {3,}/g, Te) : b,
+                k = a.cm.state.specialChars,
+                l = !1;
+            if (k.test(b))
+                for (var m = document.createDocumentFragment(), n = 0;;) {
+                    k.lastIndex = n;
+                    var o = k.exec(b),
+                        p = o ? o.index - n : b.length - n;
+                    if (p) {
+                        var q = document.createTextNode(j.slice(n, n + p));
+                        d && 9 > e ? m.appendChild(pg("span", [q])) : m.appendChild(q), a.map.push(a.pos, a.pos + p, q), a.col += p, a.pos += p
+                    }
+                    if (!o) break;
+                    if (n += p + 1, "	" == o[0]) {
+                        var r = a.cm.options.tabSize,
+                            s = r - a.col % r,
+                            q = m.appendChild(pg("span", ag(s), "cm-tab"));
+                        q.setAttribute("role", "presentation"), q.setAttribute("cm-text", "	"), a.col += s
+                    } else if ("\r" == o[0] || "\n" == o[0]) {
+                        var q = m.appendChild(pg("span", "\r" == o[0] ? "\u240d" : "\u2424", "cm-invalidchar"));
+                        q.setAttribute("cm-text", o[0]), a.col += 1
+                    } else {
+                        var q = a.cm.options.specialCharPlaceholder(o[0]);
+                        q.setAttribute("cm-text", o[0]), d && 9 > e ? m.appendChild(pg("span", [q])) : m.appendChild(q), a.col += 1
+                    }
+                    a.map.push(a.pos, a.pos + 1, q), a.pos++
+                } else {
+                    a.col += b.length;
+                    var m = document.createTextNode(j);
+                    a.map.push(a.pos, a.pos + b.length, m), d && 9 > e && (l = !0), a.pos += b.length
+                }
+            if (c || f || g || l || i) {
+                var t = c || "";
+                f && (t += f), g && (t += g);
+                var u = pg("span", [m], t, i);
+                return h && (u.title = h), a.content.appendChild(u)
+            }
+            a.content.appendChild(m)
+        }
+    }
+
+    function Te(a) {
+        for (var b = " ", c = 0; c < a.length - 2; ++c) b += c % 2 ? " " : "\xa0";
+        return b += " "
+    }
+
+    function Ue(a, b) {
+        return function (c, d, e, f, g, h, i) {
+            e = e ? e + " cm-force-border" : "cm-force-border";
+            for (var j = c.pos, k = j + d.length;;) {
+                for (var l = 0; l < b.length; l++) {
+                    var m = b[l];
+                    if (m.to > j && m.from <= j) break
+                }
+                if (m.to >= k) return a(c, d, e, f, g, h, i);
+                a(c, d.slice(0, m.to - j), e, f, null, h, i), f = null, d = d.slice(m.to - j), j = m.to
+            }
+        }
+    }
+
+    function Ve(a, b, c, d) {
+        var e = !d && c.widgetNode;
+        e && a.map.push(a.pos, a.pos + b, e), !d && a.cm.display.input.needsContentAttribute && (e || (e = a.content.appendChild(document.createElement("span"))), e.setAttribute("cm-marker", c.id)), e && (a.cm.display.input.setUneditable(e), a.content.appendChild(e)), a.pos += b
+    }
+
+    function We(a, b, c) {
+        var d = a.markedSpans,
+            e = a.text,
+            f = 0;
+        if (d)
+            for (var k, l, n, o, p, q, r, h = e.length, i = 0, g = 1, j = "", m = 0;;) {
+                if (m == i) {
+                    n = o = p = q = l = "", r = null, m = 1 / 0;
+                    for (var s = [], t = 0; t < d.length; ++t) {
+                        var u = d[t],
+                            v = u.marker;
+                        "bookmark" == v.type && u.from == i && v.widgetNode ? s.push(v) : u.from <= i && (null == u.to || u.to > i || v.collapsed && u.to == i && u.from == i) ? (null != u.to && u.to != i && m > u.to && (m = u.to, o = ""), v.className && (n += " " + v.className), v.css && (l = v.css), v.startStyle && u.from == i && (p += " " + v.startStyle), v.endStyle && u.to == m && (o += " " + v.endStyle), v.title && !q && (q = v.title), v.collapsed && (!r || ne(r.marker, v) < 0) && (r = u)) : u.from > i && m > u.from && (m = u.from)
+                    }
+                    if (r && (r.from || 0) == i) {
+                        if (Ve(b, (null == r.to ? h + 1 : r.to) - i, r.marker, null == r.from), null == r.to) return;
+                        r.to == i && (r = !1)
+                    }
+                    if (!r && s.length)
+                        for (var t = 0; t < s.length; ++t) Ve(b, 0, s[t])
+                }
+                if (i >= h) break;
+                for (var w = Math.min(h, m);;) {
+                    if (j) {
+                        var x = i + j.length;
+                        if (!r) {
+                            var y = x > w ? j.slice(0, w - i) : j;
+                            b.addToken(b, y, k ? k + n : n, p, i + y.length == m ? o : "", q, l)
+                        }
+                        if (x >= w) {
+                            j = j.slice(w - i), i = w;
+                            break
+                        }
+                        i = x, p = ""
+                    }
+                    j = e.slice(f, f = c[g++]), k = Pe(c[g++], b.cm.options)
+                }
+            } else
+                for (var g = 1; g < c.length; g += 2) b.addToken(b, e.slice(f, f = c[g]), Pe(c[g + 1], b.cm.options))
+    }
+
+    function Xe(a, b) {
+        return 0 == b.from.ch && 0 == b.to.ch && "" == bg(b.text) && (!a.cm || a.cm.options.wholeLineUpdateBefore)
+    }
+
+    function Ye(a, b, c, d) {
+        function e(a) {
+            return c ? c[a] : null
+        }
+
+        function f(a, c, e) {
+            De(a, c, e, d), Nf(a, "change", a, b)
+        }
+
+        function g(a, b) {
+            for (var c = a, f = []; b > c; ++c) f.push(new Ce(j[c], e(c), d));
+            return f
+        }
+        var h = b.from,
+            i = b.to,
+            j = b.text,
+            k = ff(a, h.line),
+            l = ff(a, i.line),
+            m = bg(j),
+            n = e(j.length - 1),
+            o = i.line - h.line;
+        if (b.full) a.insert(0, g(0, j.length)), a.remove(j.length, a.size - j.length);
+        else if (Xe(a, b)) {
+            var p = g(0, j.length - 1);
+            f(l, l.text, n), o && a.remove(h.line, o), p.length && a.insert(h.line, p)
+        } else if (k == l)
+            if (1 == j.length) f(k, k.text.slice(0, h.ch) + m + k.text.slice(i.ch), n);
+            else {
+                var p = g(1, j.length - 1);
+                p.push(new Ce(m + k.text.slice(i.ch), n, d)), f(k, k.text.slice(0, h.ch) + j[0], e(0)), a.insert(h.line + 1, p)
+            } else if (1 == j.length) f(k, k.text.slice(0, h.ch) + j[0] + l.text.slice(i.ch), e(0)), a.remove(h.line + 1, o);
+        else {
+            f(k, k.text.slice(0, h.ch) + j[0], e(0)), f(l, m + l.text.slice(i.ch), n);
+            var p = g(1, j.length - 1);
+            o > 1 && a.remove(h.line + 1, o - 1), a.insert(h.line + 1, p)
+        }
+        Nf(a, "change", a, b)
+    }
+
+    function Ze(a) {
+        this.lines = a, this.parent = null;
+        for (var b = 0, c = 0; b < a.length; ++b) a[b].parent = this, c += a[b].height;
+        this.height = c
+    }
+
+    function $e(a) {
+        this.children = a;
+        for (var b = 0, c = 0, d = 0; d < a.length; ++d) {
+            var e = a[d];
+            b += e.chunkSize(), c += e.height, e.parent = this
+        }
+        this.size = b, this.height = c, this.parent = null
+    }
+
+    function df(a, b, c) {
+        function d(a, e, f) {
+            if (a.linked)
+                for (var g = 0; g < a.linked.length; ++g) {
+                    var h = a.linked[g];
+                    if (h.doc != e) {
+                        var i = f && h.sharedHist;
+                        (!c || i) && (b(h.doc, i), d(h.doc, a, i))
+                    }
+                }
+        }
+        d(a, null, !0)
+    }
+
+    function ef(a, b) {
+        if (b.cm) throw new Error("This document is already in use.");
+        a.doc = b, b.cm = a, B(a), x(a), a.options.lineWrapping || H(a), a.options.mode = b.modeOption, ic(a)
+    }
+
+    function ff(a, b) {
+        if (b -= a.first, 0 > b || b >= a.size) throw new Error("There is no line " + (b + a.first) + " in the document.");
+        for (var c = a; !c.lines;)
+            for (var d = 0;; ++d) {
+                var e = c.children[d],
+                    f = e.chunkSize();
+                if (f > b) {
+                    c = e;
+                    break
+                }
+                b -= f
+            }
+        return c.lines[b]
+    }
+
+    function gf(a, b, c) {
+        var d = [],
+            e = b.line;
+        return a.iter(b.line, c.line + 1, function (a) {
+            var f = a.text;
+            e == c.line && (f = f.slice(0, c.ch)), e == b.line && (f = f.slice(b.ch)), d.push(f), ++e
+        }), d
+    }
+
+    function hf(a, b, c) {
+        var d = [];
+        return a.iter(b, c, function (a) {
+            d.push(a.text)
+        }), d
+    }
+
+    function jf(a, b) {
+        var c = b - a.height;
+        if (c)
+            for (var d = a; d; d = d.parent) d.height += c
+    }
+
+    function kf(a) {
+        if (null == a.parent) return null;
+        for (var b = a.parent, c = dg(b.lines, a), d = b.parent; d; b = d, d = d.parent)
+            for (var e = 0; d.children[e] != b; ++e) c += d.children[e].chunkSize();
+        return c + b.first
+    }
+
+    function lf(a, b) {
+        var c = a.first;
+        a: do {
+            for (var d = 0; d < a.children.length; ++d) {
+                var e = a.children[d],
+                    f = e.height;
+                if (f > b) {
+                    a = e;
+                    continue a
+                }
+                b -= f, c += e.chunkSize()
+            }
+            return c
+        } while (!a.lines);
+        for (var d = 0; d < a.lines.length; ++d) {
+            var g = a.lines[d],
+                h = g.height;
+            if (h > b) break;
+            b -= h
+        }
+        return c + d
+    }
+
+    function mf(a) {
+        a = se(a);
+        for (var b = 0, c = a.parent, d = 0; d < c.lines.length; ++d) {
+            var e = c.lines[d];
+            if (e == a) break;
+            b += e.height
+        }
+        for (var f = c.parent; f; c = f, f = c.parent)
+            for (var d = 0; d < f.children.length; ++d) {
+                var g = f.children[d];
+                if (g == c) break;
+                b += g.height
+            }
+        return b
+    }
+
+    function nf(a) {
+        var b = a.order;
+        return null == b && (b = a.order = ah(a.text)), b
+    }
+
+    function of(a) {
+        this.done = [], this.undone = [], this.undoDepth = 1 / 0, this.lastModTime = this.lastSelTime = 0, this.lastOp = this.lastSelOp = null, this.lastOrigin = this.lastSelOrigin = null, this.generation = this.maxGeneration = a || 1
+    }
+
+    function pf(a, b) {
+        var c = {
+            from: qa(b.from),
+            to: bd(b),
+            text: gf(a, b.from, b.to)
+        };
+        return wf(a, c, b.from.line, b.to.line + 1), df(a, function (a) {
+            wf(a, c, b.from.line, b.to.line + 1)
+        }, !0), c
+    }
+
+    function qf(a) {
+        for (; a.length;) {
+            var b = bg(a);
+            if (!b.ranges) break;
+            a.pop()
+        }
+    }
+
+    function rf(a, b) {
+        return b ? (qf(a.done), bg(a.done)) : a.done.length && !bg(a.done)
+            .ranges ? bg(a.done) : a.done.length > 1 && !a.done[a.done.length - 2].ranges ? (a.done.pop(), bg(a.done)) : void 0
+    }
+
+    function sf(a, b, c, d) {
+        var e = a.history;
+        e.undone.length = 0;
+        var g, f = +new Date;
+        if ((e.lastOp == d || e.lastOrigin == b.origin && b.origin && ("+" == b.origin.charAt(0) && a.cm && e.lastModTime > f - a.cm.options.historyEventDelay || "*" == b.origin.charAt(0))) && (g = rf(e, e.lastOp == d))) {
+            var h = bg(g.changes);
+            0 == pa(b.from, b.to) && 0 == pa(b.from, h.to) ? h.to = bd(b) : g.changes.push(pf(a, b))
+        } else {
+            var i = bg(e.done);
+            for (i && i.ranges || vf(a.sel, e.done), g = {
+                    changes: [pf(a, b)],
+                    generation: e.generation
+                }, e.done.push(g); e.done.length > e.undoDepth;) e.done.shift(), e.done[0].ranges || e.done.shift()
+        }
+        e.done.push(c), e.generation = ++e.maxGeneration, e.lastModTime = e.lastSelTime = f, e.lastOp = e.lastSelOp = d, e.lastOrigin = e.lastSelOrigin = b.origin, h || Lf(a, "historyAdded")
+    }
+
+    function tf(a, b, c, d) {
+        var e = b.charAt(0);
+        return "*" == e || "+" == e && c.ranges.length == d.ranges.length && c.somethingSelected() == d.somethingSelected() && new Date - a.history.lastSelTime <= (a.cm ? a.cm.options.historyEventDelay : 500)
+    }
+
+    function uf(a, b, c, d) {
+        var e = a.history,
+            f = d && d.origin;
+        c == e.lastSelOp || f && e.lastSelOrigin == f && (e.lastModTime == e.lastSelTime && e.lastOrigin == f || tf(a, f, bg(e.done), b)) ? e.done[e.done.length - 1] = b : vf(b, e.done), e.lastSelTime = +new Date, e.lastSelOrigin = f, e.lastSelOp = c, d && d.clearRedo !== !1 && qf(e.undone)
+    }
+
+    function vf(a, b) {
+        var c = bg(b);
+        c && c.ranges && c.equals(a) || b.push(a)
+    }
+
+    function wf(a, b, c, d) {
+        var e = b["spans_" + a.id],
+            f = 0;
+        a.iter(Math.max(a.first, c), Math.min(a.first + a.size, d), function (c) {
+            c.markedSpans && ((e || (e = b["spans_" + a.id] = {}))[f] = c.markedSpans), ++f
+        })
+    }
+
+    function xf(a) {
+        if (!a) return null;
+        for (var c, b = 0; b < a.length; ++b) a[b].marker.explicitlyCleared ? c || (c = a.slice(0, b)) : c && c.push(a[b]);
+        return c ? c.length ? c : null : a
+    }
+
+    function yf(a, b) {
+        var c = b["spans_" + a.id];
+        if (!c) return null;
+        for (var d = 0, e = []; d < b.text.length; ++d) e.push(xf(c[d]));
+        return e
+    }
+
+    function zf(a, b, c) {
+        for (var d = 0, e = []; d < a.length; ++d) {
+            var f = a[d];
+            if (f.ranges) e.push(c ? Ja.prototype.deepCopy.call(f) : f);
+            else {
+                var g = f.changes,
+                    h = [];
+                e.push({
+                    changes: h
+                });
+                for (var i = 0; i < g.length; ++i) {
+                    var k, j = g[i];
+                    if (h.push({
+                            from: j.from,
+                            to: j.to,
+                            text: j.text
+                        }), b)
+                        for (var l in j)(k = l.match(/^spans_(\d+)$/)) && dg(b, Number(k[1])) > -1 && (bg(h)[l] = j[l], delete j[l])
+                }
+            }
+        }
+        return e
+    }
+
+    function Af(a, b, c, d) {
+        c < a.line ? a.line += d : b < a.line && (a.line = b, a.ch = 0)
+    }
+
+    function Bf(a, b, c, d) {
+        for (var e = 0; e < a.length; ++e) {
+            var f = a[e],
+                g = !0;
+            if (f.ranges) {
+                f.copied || (f = a[e] = f.deepCopy(), f.copied = !0);
+                for (var h = 0; h < f.ranges.length; h++) Af(f.ranges[h].anchor, b, c, d), Af(f.ranges[h].head, b, c, d)
+            } else {
+                for (var h = 0; h < f.changes.length; ++h) {
+                    var i = f.changes[h];
+                    if (c < i.from.line) i.from = oa(i.from.line + d, i.from.ch), i.to = oa(i.to.line + d, i.to.ch);
+                    else if (b <= i.to.line) {
+                        g = !1;
+                        break
+                    }
+                }
+                g || (a.splice(0, e + 1), e = 0)
+            }
+        }
+    }
+
+    function Cf(a, b) {
+        var c = b.from.line,
+            d = b.to.line,
+            e = b.text.length - (d - c) - 1;
+        Bf(a.done, c, d, e), Bf(a.undone, c, d, e)
+    }
+
+    function Ff(a) {
+        return null != a.defaultPrevented ? a.defaultPrevented : 0 == a.returnValue
+    }
+
+    function Hf(a) {
+        return a.target || a.srcElement
+    }
+
+    function If(a) {
+        var b = a.which;
+        return null == b && (1 & a.button ? b = 1 : 2 & a.button ? b = 3 : 4 & a.button && (b = 2)), o && a.ctrlKey && 1 == b && (b = 3), b
+    }
+
+    function Nf(a, b) {
+        function f(a) {
+            return function () {
+                a.apply(null, d)
+            }
+        }
+        var c = a._handlers && a._handlers[b];
+        if (c) {
+            var e, d = Array.prototype.slice.call(arguments, 2);
+            Tb ? e = Tb.delayedCallbacks : Mf ? e = Mf : (e = Mf = [], setTimeout(Of, 0));
+            for (var g = 0; g < c.length; ++g) e.push(f(c[g]))
+        }
+    }
+
+    function Of() {
+        var a = Mf;
+        Mf = null;
+        for (var b = 0; b < a.length; ++b) a[b]()
+    }
+
+    function Pf(a, b, c) {
+        return "string" == typeof b && (b = {
+            type: b,
+            preventDefault: function () {
+                this.defaultPrevented = !0
+            }
+        }), Lf(a, c || b.type, a, b), Ff(b) || b.codemirrorIgnore
+    }
+
+    function Qf(a) {
+        var b = a._handlers && a._handlers.cursorActivity;
+        if (b)
+            for (var c = a.curOp.cursorActivityHandlers || (a.curOp.cursorActivityHandlers = []), d = 0; d < b.length; ++d) - 1 == dg(c, b[d]) && c.push(b[d])
+    }
+
+    function Rf(a, b) {
+        var c = a._handlers && a._handlers[b];
+        return c && c.length > 0
+    }
+
+    function Sf(a) {
+        a.prototype.on = function (a, b) {
+            Jf(this, a, b)
+        }, a.prototype.off = function (a, b) {
+            Kf(this, a, b)
+        }
+    }
+
+    function Yf() {
+        this.id = null
+    }
+
+    function ag(a) {
+        for (; _f.length <= a;) _f.push(bg(_f) + " ");
+        return _f[a]
+    }
+
+    function bg(a) {
+        return a[a.length - 1]
+    }
+
+    function dg(a, b) {
+        for (var c = 0; c < a.length; ++c)
+            if (a[c] == b) return c;
+        return -1
+    }
+
+    function eg(a, b) {
+        for (var c = [], d = 0; d < a.length; d++) c[d] = b(a[d], d);
+        return c
+    }
+
+    function fg() {}
+
+    function gg(a, b) {
+        var c;
+        return Object.create ? c = Object.create(a) : (fg.prototype = a, c = new fg), b && hg(b, c), c
+    }
+
+    function hg(a, b, c) {
+        b || (b = {});
+        for (var d in a) !a.hasOwnProperty(d) || c === !1 && b.hasOwnProperty(d) || (b[d] = a[d]);
+        return b
+    }
+
+    function ig(a) {
+        var b = Array.prototype.slice.call(arguments, 1);
+        return function () {
+            return a.apply(null, b)
+        }
+    }
+
+    function lg(a, b) {
+        return b ? b.source.indexOf("\\w") > -1 && kg(a) ? !0 : b.test(a) : kg(a)
+    }
+
+    function mg(a) {
+        for (var b in a)
+            if (a.hasOwnProperty(b) && a[b]) return !1;
+        return !0
+    }
+
+    function og(a) {
+        return a.charCodeAt(0) >= 768 && ng.test(a)
+    }
+
+    function pg(a, b, c, d) {
+        var e = document.createElement(a);
+        if (c && (e.className = c), d && (e.style.cssText = d), "string" == typeof b) e.appendChild(document.createTextNode(b));
+        else if (b)
+            for (var f = 0; f < b.length; ++f) e.appendChild(b[f]);
+        return e
+    }
+
+    function rg(a) {
+        for (var b = a.childNodes.length; b > 0; --b) a.removeChild(a.firstChild);
+        return a
+    }
+
+    function sg(a, b) {
+        return rg(a)
+            .appendChild(b)
+    }
+
+    function ug() {
+        for (var a = document.activeElement; a && a.root && a.root.activeElement;) a = a.root.activeElement;
+        return a
+    }
+
+    function vg(a) {
+        return new RegExp("(^|\\s)" + a + "(?:$|\\s)\\s*")
+    }
+
+    function yg(a, b) {
+        for (var c = a.split(" "), d = 0; d < c.length; d++) c[d] && !vg(c[d])
+            .test(b) && (b += " " + c[d]);
+        return b
+    }
+
+    function zg(a) {
+        if (document.body.getElementsByClassName)
+            for (var b = document.body.getElementsByClassName("CodeMirror"), c = 0; c < b.length; c++) {
+                var d = b[c].CodeMirror;
+                d && a(d)
+            }
+    }
+
+    function Bg() {
+        Ag || (Cg(), Ag = !0)
+    }
+
+    function Cg() {
+        var a;
+        Jf(window, "resize", function () {
+            null == a && (a = setTimeout(function () {
+                a = null, zg(rc)
+            }, 100))
+        }), Jf(window, "blur", function () {
+            zg($c)
+        })
+    }
+
+    function Fg(a) {
+        if (null == Eg) {
+            var b = pg("span", "\u200b");
+            sg(a, pg("span", [b, document.createTextNode("x")])), 0 != a.firstChild.offsetHeight && (Eg = b.offsetWidth <= 1 && b.offsetHeight > 2 && !(d && 8 > e))
+        }
+        var c = Eg ? pg("span", "\u200b") : pg("span", "\xa0", null, "display: inline-block; width: 1px; margin-right: -1px");
+        return c.setAttribute("cm-text", ""), c
+    }
+
+    function Hg(a) {
+        if (oldff) return false;
+        if (null != Gg) return Gg;
+        var b = sg(a, document.createTextNode("A\u062eA")),
+            c = qg(b, 0, 1)
+            .getBoundingClientRect();
+        if (!c || c.left == c.right) return !1;
+        var d = qg(b, 1, 2)
+            .getBoundingClientRect();
+        return Gg = d.right - c.right < 3
+    }
+
+    function Mg(a) {
+        if (null != Lg) return Lg;
+        var b = sg(a, pg("span", "x")),
+            c = b.getBoundingClientRect(),
+            d = qg(b, 0, 1)
+            .getBoundingClientRect();
+        return Lg = Math.abs(c.left - d.left) > 1
+    }
+
+    function Og(a, b, c, d) {
+        if (!a) return d(b, c, "ltr");
+        for (var e = !1, f = 0; f < a.length; ++f) {
+            var g = a[f];
+            (g.from < c && g.to > b || b == c && g.to == b) && (d(Math.max(g.from, b), Math.min(g.to, c), 1 == g.level ? "rtl" : "ltr"), e = !0)
+        }
+        e || d(b, c, "ltr")
+    }
+
+    function Pg(a) {
+        return a.level % 2 ? a.to : a.from
+    }
+
+    function Qg(a) {
+        return a.level % 2 ? a.from : a.to
+    }
+
+    function Rg(a) {
+        var b = nf(a);
+        return b ? Pg(b[0]) : 0
+    }
+
+    function Sg(a) {
+        var b = nf(a);
+        return b ? Qg(bg(b)) : a.text.length
+    }
+
+    function Tg(a, b) {
+        var c = ff(a.doc, b),
+            d = se(c);
+        d != c && (b = kf(d));
+        var e = nf(d),
+            f = e ? e[0].level % 2 ? Sg(d) : Rg(d) : 0;
+        return oa(b, f)
+    }
+
+    function Ug(a, b) {
+        for (var c, d = ff(a.doc, b); c = qe(d);) d = c.find(1, !0)
+            .line, b = null;
+        var e = nf(d),
+            f = e ? e[0].level % 2 ? Rg(d) : Sg(d) : d.text.length;
+        return oa(null == b ? kf(d) : b, f)
+    }
+
+    function Vg(a, b) {
+        var c = Tg(a, b.line),
+            d = ff(a.doc, c.line),
+            e = nf(d);
+        if (!e || 0 == e[0].level) {
+            var f = Math.max(0, d.text.search(/\S/)),
+                g = b.line == c.line && b.ch <= f && b.ch;
+            return oa(c.line, g ? 0 : f)
+        }
+        return c
+    }
+
+    function Wg(a, b, c) {
+        var d = a[0].level;
+        return b == d ? !0 : c == d ? !1 : c > b
+    }
+
+    function Yg(a, b) {
+        Xg = null;
+        for (var d, c = 0; c < a.length; ++c) {
+            var e = a[c];
+            if (e.from < b && e.to > b) return c;
+            if (e.from == b || e.to == b) {
+                if (null != d) return Wg(a, e.level, a[d].level) ? (e.from != e.to && (Xg = d), c) : (e.from != e.to && (Xg = c), d);
+                d = c
+            }
+        }
+        return d
+    }
+
+    function Zg(a, b, c, d) {
+        if (!d) return b + c;
+        do b += c; while (b > 0 && og(a.text.charAt(b)));
+        return b
+    }
+
+    function $g(a, b, c, d) {
+        var e = nf(a);
+        if (!e) return _g(a, b, c, d);
+        for (var f = Yg(e, b), g = e[f], h = Zg(a, b, g.level % 2 ? -c : c, d);;) {
+            if (h > g.from && h < g.to) return h;
+            if (h == g.from || h == g.to) return Yg(e, h) == f ? h : (g = e[f += c], c > 0 == g.level % 2 ? g.to : g.from);
+            if (g = e[f += c], !g) return null;
+            h = c > 0 == g.level % 2 ? Zg(a, g.to, -1, d) : Zg(a, g.from, 1, d)
+        }
+    }
+
+    function _g(a, b, c, d) {
+        var e = b + c;
+        if (d)
+            for (; e > 0 && og(a.text.charAt(e));) e += c;
+        return 0 > e || e > a.text.length ? null : e
+    }
+    var a = /gecko\/\d/i.test(navigator.userAgent),
+        b = /MSIE \d/.test(navigator.userAgent),
+        c = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent),
+        d = b || c,
+        e = d && (b ? document.documentMode || 6 : c[1]),
+        f = /WebKit\//.test(navigator.userAgent),
+        g = f && /Qt\/\d+\.\d+/.test(navigator.userAgent),
+        h = /Chrome\//.test(navigator.userAgent),
+        i = /Opera\//.test(navigator.userAgent),
+        j = /Apple Computer/.test(navigator.vendor),
+        k = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent),
+        l = /PhantomJS/.test(navigator.userAgent),
+        m = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent),
+        n = m || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent),
+        o = m || /Mac/.test(navigator.platform),
+        p = /win/i.test(navigator.platform),
+        q = i && navigator.userAgent.match(/Version\/(\d*\.\d*)/),
+        oldff = /Firefox\/([1-3])\./i.test(navigator.userAgent);
+    q && (q = Number(q[1])), q && q >= 15 && (i = !1, f = !0);
+    var r = o && (g || i && (null == q || 12.11 > q)),
+        s = a || d && e >= 9,
+        t = !1,
+        u = !1;
+    K.prototype = hg({
+        update: function (a) {
+            var b = a.scrollWidth > a.clientWidth + 1,
+                c = a.scrollHeight > a.clientHeight + 1,
+                d = a.nativeBarWidth;
+            if (c) {
+                this.vert.style.display = "block", this.vert.style.bottom = b ? d + "px" : "0";
+                var e = a.viewHeight - (b ? d : 0);
+                this.vert.firstChild.style.height = Math.max(0, a.scrollHeight - a.clientHeight + e) + "px"
+            } else this.vert.style.display = "", this.vert.firstChild.style.height = "0";
+            if (b) {
+                this.horiz.style.display = "block", this.horiz.style.right = c ? d + "px" : "0", this.horiz.style.left = a.barLeft + "px";
+                var f = a.viewWidth - a.barLeft - (c ? d : 0);
+                this.horiz.firstChild.style.width = a.scrollWidth - a.clientWidth + f + "px"
+            } else this.horiz.style.display = "", this.horiz.firstChild.style.width = "0";
+            return !this.checkedOverlay && a.clientHeight > 0 && (0 == d && this.overlayHack(), this.checkedOverlay = !0), {
+                right: c ? d : 0,
+                bottom: b ? d : 0
+            }
+        },
+        setScrollLeft: function (a) {
+            this.horiz.scrollLeft != a && (this.horiz.scrollLeft = a)
+        },
+        setScrollTop: function (a) {
+            this.vert.scrollTop != a && (this.vert.scrollTop = a)
+        },
+        overlayHack: function () {
+            var a = o && !k ? "12px" : "18px";
+            this.horiz.style.minHeight = this.vert.style.minWidth = a;
+            var b = this,
+                c = function (a) {
+                    Hf(a) != b.vert && Hf(a) != b.horiz && dc(b.cm, uc)(a)
+                };
+            Jf(this.vert, "mousedown", c), Jf(this.horiz, "mousedown", c)
+        },
+        clear: function () {
+            var a = this.horiz.parentNode;
+            a.removeChild(this.horiz), a.removeChild(this.vert)
+        }
+    }, K.prototype), L.prototype = hg({
+        update: function () {
+            return {
+                bottom: 0,
+                right: 0
+            }
+        },
+        setScrollLeft: function () {},
+        setScrollTop: function () {},
+        clear: function () {}
+    }, L.prototype), v.scrollbarModel = {
+        "native": K,
+        "null": L
+    }, U.prototype.signal = function (a, b) {
+        Rf(a, b) && this.events.push(arguments)
+    }, U.prototype.finish = function () {
+        for (var a = 0; a < this.events.length; a++) Lf.apply(null, this.events[a])
+    };
+    var oa = v.Pos = function (a, b) {
+            return this instanceof oa ? (this.line = a, void(this.ch = b)) : new oa(a, b)
+        },
+        pa = v.cmpPos = function (a, b) {
+            return a.line - b.line || a.ch - b.ch
+        },
+        va = null;
+    Ba.prototype = hg({
+        init: function (a) {
+            function h(a) {
+                if (c.somethingSelected()) va = c.getSelections(), b.inaccurateSelection && (b.prevInput = "", b.inaccurateSelection = !1, g.value = va.join("\n"), cg(g));
+                else {
+                    if (!c.options.lineWiseCopyCut) return;
+                    var d = za(c);
+                    va = d.text, "cut" == a.type ? c.setSelections(d.ranges, null, Vf) : (b.prevInput = "", g.value = d.text.join("\n"), cg(g))
+                }
+                "cut" == a.type && (c.state.cutIncoming = !0)
+            }
+            var b = this,
+                c = this.cm,
+                f = this.wrapper = Ca(),
+                g = this.textarea = f.firstChild;
+            a.wrapper.insertBefore(f, a.wrapper.firstChild), m && (g.style.width = "0px"), Jf(g, "input", function () {
+                d && e >= 9 && b.hasSelection && (b.hasSelection = null), b.poll()
+            }), Jf(g, "paste", function (a) {
+                return xa(a, c) ? !0 : (c.state.pasteIncoming = !0, void b.fastPoll())
+            }), Jf(g, "cut", h), Jf(g, "copy", h), Jf(a.scroller, "paste", function (d) {
+                sc(a, d) || (c.state.pasteIncoming = !0, b.focus())
+            }), Jf(a.lineSpace, "selectstart", function (b) {
+                sc(a, b) || Df(b)
+            }), Jf(g, "compositionstart", function () {
+                var a = c.getCursor("from");
+                b.composing = {
+                    start: a,
+                    range: c.markText(a, c.getCursor("to"), {
+                        className: "CodeMirror-composing"
+                    })
+                }
+            }), Jf(g, "compositionend", function () {
+                b.composing && (b.poll(), b.composing.range.clear(), b.composing = null)
+            })
+        },
+        prepareSelection: function () {
+            var a = this.cm,
+                b = a.display,
+                c = a.doc,
+                d = eb(a);
+            if (a.options.moveInputWithCursor) {
+                var e = Lb(a, c.sel.primary()
+                        .head, "div"),
+                    f = b.wrapper.getBoundingClientRect(),
+                    g = b.lineDiv.getBoundingClientRect();
+                d.teTop = Math.max(0, Math.min(b.wrapper.clientHeight - 10, e.top + g.top - f.top)), d.teLeft = Math.max(0, Math.min(b.wrapper.clientWidth - 10, e.left + g.left - f.left))
+            }
+            return d
+        },
+        showSelection: function (a) {
+            var b = this.cm,
+                c = b.display;
+            sg(c.cursorDiv, a.cursors), sg(c.selectionDiv, a.selection), null != a.teTop && (this.wrapper.style.top = a.teTop + "px", this.wrapper.style.left = a.teLeft + "px")
+        },
+        reset: function (a) {
+            if (!this.contextMenuPending) {
+                var b, c, f = this.cm,
+                    g = f.doc;
+                if (f.somethingSelected()) {
+                    this.prevInput = "";
+                    var h = g.sel.primary();
+                    b = Kg && (h.to()
+                        .line - h.from()
+                        .line > 100 || (c = f.getSelection())
+                        .length > 1e3);
+                    var i = b ? "-" : c || f.getSelection();
+                    this.textarea.value = i, f.state.focused && cg(this.textarea), d && e >= 9 && (this.hasSelection = i)
+                } else a || (this.prevInput = this.textarea.value = "", d && e >= 9 && (this.hasSelection = null));
+                this.inaccurateSelection = b
+            }
+        },
+        getField: function () {
+            return this.textarea
+        },
+        supportsTouch: function () {
+            return !1
+        },
+        focus: function () {
+            if ("nocursor" != this.cm.options.readOnly && (!n || ug() != this.textarea)) try {
+                this.textarea.focus()
+            } catch (a) {}
+        },
+        blur: function () {
+            this.textarea.blur()
+        },
+        resetPosition: function () {
+            this.wrapper.style.top = this.wrapper.style.left = 0
+        },
+        receivedFocus: function () {
+            this.slowPoll()
+        },
+        slowPoll: function () {
+            var a = this;
+            a.pollingFast || a.polling.set(this.cm.options.pollInterval, function () {
+                a.poll(), a.cm.state.focused && a.slowPoll()
+            })
+        },
+        fastPoll: function () {
+            function c() {
+                var d = b.poll();
+                d || a ? (b.pollingFast = !1, b.slowPoll()) : (a = !0, b.polling.set(60, c))
+            }
+            var a = !1,
+                b = this;
+            b.pollingFast = !0, b.polling.set(20, c)
+        },
+        poll: function () {
+            var a = this.cm,
+                b = this.textarea,
+                c = this.prevInput;
+            if (this.contextMenuPending || !a.state.focused || Jg(b) && !c && !this.composing || ua(a) || a.options.disableInput || a.state.keySeq) return !1;
+            var f = b.value;
+            if (f == c && !a.somethingSelected()) return !1;
+            if (d && e >= 9 && this.hasSelection === f || o && /[\uf700-\uf7ff]/.test(f)) return a.display.input.reset(), !1;
+            if (a.doc.sel == a.display.selForContextMenu) {
+                var g = f.charCodeAt(0);
+                if (8203 != g || c || (c = "\u200b"), 8666 == g) return this.reset(), this.cm.execCommand("undo")
+            }
+            for (var h = 0, i = Math.min(c.length, f.length); i > h && c.charCodeAt(h) == f.charCodeAt(h);) ++h;
+            var j = this;
+            return cc(a, function () {
+                wa(a, f.slice(h), c.length - h, null, j.composing ? "*compose" : null), f.length > 1e3 || f.indexOf("\n") > -1 ? b.value = j.prevInput = "" : j.prevInput = f, j.composing && (j.composing.range.clear(), j.composing.range = a.markText(j.composing.start, a.getCursor("to"), {
+                    className: "CodeMirror-composing"
+                }))
+            }), !0
+        },
+        ensurePolled: function () {
+            this.pollingFast && this.poll() && (this.pollingFast = !1)
+        },
+        onKeyPress: function () {
+            d && e >= 9 && (this.hasSelection = null), this.fastPoll()
+        },
+        onContextMenu: function (a) {
+            function o() {
+                if (null != h.selectionStart) {
+                    var a = c.somethingSelected(),
+                        d = "\u200b" + (a ? h.value : "");
+                    h.value = "\u21da", h.value = d, b.prevInput = a ? "" : "\u200b", h.selectionStart = 1, h.selectionEnd = d.length, g.selForContextMenu = c.doc.sel
+                }
+            }
+
+            function p() {
+                if (b.contextMenuPending = !1, b.wrapper.style.position = "relative", h.style.cssText = m, d && 9 > e && g.scrollbars.setScrollTop(g.scroller.scrollTop = k), null != h.selectionStart) {
+                    (!d || d && 9 > e) && o();
+                    var a = 0,
+                        f = function () {
+                            g.selForContextMenu == c.doc.sel && 0 == h.selectionStart && h.selectionEnd > 0 && "\u200b" == b.prevInput ? dc(c, Ld.selectAll)(c) : a++ < 10 ? g.detectingSelectAll = setTimeout(f, 500) : g.input.reset()
+                        };
+                    g.detectingSelectAll = setTimeout(f, 200)
+                }
+            }
+            var b = this,
+                c = b.cm,
+                g = c.display,
+                h = b.textarea,
+                j = tc(c, a),
+                k = g.scroller.scrollTop;
+            if (j && !i) {
+                var l = c.options.resetSelectionOnContextMenu;
+                l && -1 == c.doc.sel.contains(j) && dc(c, Za)(c.doc, Ma(j), Vf);
+                var m = h.style.cssText;
+                if (b.wrapper.style.position = "absolute", h.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (a.clientY - 5) + "px; left: " + (a.clientX - 5) + "px; z-index: 1000; background: " + (d ? "rgba(255, 255, 255, .05)" : "transparent") + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);", f) var n = window.scrollY;
+                if (g.input.focus(), f && window.scrollTo(null, n), g.input.reset(), c.somethingSelected() || (h.value = b.prevInput = " "), b.contextMenuPending = !0, g.selForContextMenu = c.doc.sel, clearTimeout(g.detectingSelectAll), d && e >= 9 && o(), s) {
+                    Gf(a);
+                    var q = function () {
+                        Kf(window, "mouseup", q), setTimeout(p, 20)
+                    };
+                    Jf(window, "mouseup", q)
+                } else setTimeout(p, 50)
+            }
+        },
+        setUneditable: fg,
+        needsContentAttribute: !1
+    }, Ba.prototype), Da.prototype = hg({
+        init: function (a) {
+            function e(a) {
+                if (c.somethingSelected()) va = c.getSelections(), "cut" == a.type && c.replaceSelection("", null, "cut");
+                else {
+                    if (!c.options.lineWiseCopyCut) return;
+                    var b = za(c);
+                    va = b.text, "cut" == a.type && c.operation(function () {
+                        c.setSelections(b.ranges, 0, Vf), c.replaceSelection("", null, "cut")
+                    })
+                }
+                if (a.clipboardData && !m) a.preventDefault(), a.clipboardData.clearData(), a.clipboardData.setData("text/plain", va.join("\n"));
+                else {
+                    var d = Ca(),
+                        e = d.firstChild;
+                    c.display.lineSpace.insertBefore(d, c.display.lineSpace.firstChild), e.value = va.join("\n");
+                    var f = document.activeElement;
+                    cg(e), setTimeout(function () {
+                        c.display.lineSpace.removeChild(d), f.focus()
+                    }, 50)
+                }
+            }
+            var b = this,
+                c = b.cm,
+                d = b.div = a.lineDiv;
+            d.contentEditable = "true", Aa(d), Jf(d, "paste", function (a) {
+                xa(a, c)
+            }), Jf(d, "compositionstart", function (a) {
+                var d = a.data;
+                if (b.composing = {
+                        sel: c.doc.sel,
+                        data: d,
+                        startData: d
+                    }, d) {
+                    var e = c.doc.sel.primary(),
+                        f = c.getLine(e.head.line),
+                        g = f.indexOf(d, Math.max(0, e.head.ch - d.length));
+                    g > -1 && g <= e.head.ch && (b.composing.sel = Ma(oa(e.head.line, g), oa(e.head.line, g + d.length)))
+                }
+            }), Jf(d, "compositionupdate", function (a) {
+                b.composing.data = a.data
+            }), Jf(d, "compositionend", function (a) {
+                var c = b.composing;
+                c && (a.data == c.startData || /\u200b/.test(a.data) || (c.data = a.data), setTimeout(function () {
+                    c.handled || b.applyComposition(c), b.composing == c && (b.composing = null)
+                }, 50))
+            }), Jf(d, "touchstart", function () {
+                b.forceCompositionEnd()
+            }), Jf(d, "input", function () {
+                b.composing || b.pollContent() || cc(b.cm, function () {
+                    ic(c)
+                })
+            }), Jf(d, "copy", e), Jf(d, "cut", e)
+        },
+        prepareSelection: function () {
+            var a = eb(this.cm, !1);
+            return a.focus = this.cm.state.focused, a
+        },
+        showSelection: function (a) {
+            a && this.cm.display.view.length && (a.focus && this.showPrimarySelection(), this.showMultipleSelections(a))
+        },
+        showPrimarySelection: function () {
+            var b = window.getSelection(),
+                c = this.cm.doc.sel.primary(),
+                d = Ga(this.cm, b.anchorNode, b.anchorOffset),
+                e = Ga(this.cm, b.focusNode, b.focusOffset);
+            if (!d || d.bad || !e || e.bad || 0 != pa(sa(d, e), c.from()) || 0 != pa(ra(d, e), c.to())) {
+                var f = Ea(this.cm, c.from()),
+                    g = Ea(this.cm, c.to());
+                if (f || g) {
+                    var h = this.cm.display.view,
+                        i = b.rangeCount && b.getRangeAt(0);
+                    if (f) {
+                        if (!g) {
+                            var j = h[h.length - 1].measure,
+                                k = j.maps ? j.maps[j.maps.length - 1] : j.map;
+                            g = {
+                                node: k[k.length - 1],
+                                offset: k[k.length - 2] - k[k.length - 3]
+                            }
+                        }
+                    } else f = {
+                        node: h[0].measure.map[2],
+                        offset: 0
+                    };
+                    try {
+                        var l = qg(f.node, f.offset, g.offset, g.node)
+                    } catch (m) {}
+                    l && (b.removeAllRanges(), b.addRange(l), i && null == b.anchorNode ? b.addRange(i) : a && this.startGracePeriod()), this.rememberSelection()
+                }
+            }
+        },
+        startGracePeriod: function () {
+            var a = this;
+            clearTimeout(this.gracePeriod), this.gracePeriod = setTimeout(function () {
+                a.gracePeriod = !1, a.selectionChanged() && a.cm.operation(function () {
+                    a.cm.curOp.selectionChanged = !0
+                })
+            }, 20)
+        },
+        showMultipleSelections: function (a) {
+            sg(this.cm.display.cursorDiv, a.cursors), sg(this.cm.display.selectionDiv, a.selection)
+        },
+        rememberSelection: function () {
+            var a = window.getSelection();
+            this.lastAnchorNode = a.anchorNode, this.lastAnchorOffset = a.anchorOffset, this.lastFocusNode = a.focusNode, this.lastFocusOffset = a.focusOffset
+        },
+        selectionInEditor: function () {
+            var a = window.getSelection();
+            if (!a.rangeCount) return !1;
+            var b = a.getRangeAt(0)
+                .commonAncestorContainer;
+            return tg(this.div, b)
+        },
+        focus: function () {
+            "nocursor" != this.cm.options.readOnly && this.div.focus()
+        },
+        blur: function () {
+            this.div.blur()
+        },
+        getField: function () {
+            return this.div
+        },
+        supportsTouch: function () {
+            return !0
+        },
+        receivedFocus: function () {
+            function b() {
+                a.cm.state.focused && (a.pollSelection(), a.polling.set(a.cm.options.pollInterval, b))
+            }
+            var a = this;
+            this.selectionInEditor() ? this.pollSelection() : cc(this.cm, function () {
+                a.cm.curOp.selectionChanged = !0
+            }), this.polling.set(this.cm.options.pollInterval, b)
+        },
+        selectionChanged: function () {
+            var a = window.getSelection();
+            return a.anchorNode != this.lastAnchorNode || a.anchorOffset != this.lastAnchorOffset || a.focusNode != this.lastFocusNode || a.focusOffset != this.lastFocusOffset
+        },
+        pollSelection: function () {
+            if (!this.composing && !this.gracePeriod && this.selectionChanged()) {
+                var a = window.getSelection(),
+                    b = this.cm;
+                this.rememberSelection();
+                var c = Ga(b, a.anchorNode, a.anchorOffset),
+                    d = Ga(b, a.focusNode, a.focusOffset);
+                c && d && cc(b, function () {
+                    Za(b.doc, Ma(c, d), Vf), (c.bad || d.bad) && (b.curOp.selectionChanged = !0)
+                })
+            }
+        },
+        pollContent: function () {
+            var a = this.cm,
+                b = a.display,
+                c = a.doc.sel.primary(),
+                d = c.from(),
+                e = c.to();
+            if (d.line < b.viewFrom || e.line > b.viewTo - 1) return !1;
+            var f;
+            if (d.line == b.viewFrom || 0 == (f = lc(a, d.line))) var g = kf(b.view[0].line),
+                h = b.view[0].node;
+            else var g = kf(b.view[f].line),
+                h = b.view[f - 1].node.nextSibling;
+            var i = lc(a, e.line);
+            if (i == b.view.length - 1) var j = b.viewTo - 1,
+                k = b.lineDiv.lastChild;
+            else var j = kf(b.view[i + 1].line) - 1,
+                k = b.view[i + 1].node.previousSibling;
+            for (var l = a.doc.splitLines(Ia(a, h, k, g, j)), m = gf(a.doc, oa(g, 0), oa(j, ff(a.doc, j)
+                    .text.length)); l.length > 1 && m.length > 1;)
+                if (bg(l) == bg(m)) l.pop(), m.pop(), j--;
+                else {
+                    if (l[0] != m[0]) break;
+                    l.shift(), m.shift(), g++
+                }
+            for (var n = 0, o = 0, p = l[0], q = m[0], r = Math.min(p.length, q.length); r > n && p.charCodeAt(n) == q.charCodeAt(n);) ++n;
+            for (var s = bg(l), t = bg(m), u = Math.min(s.length - (1 == l.length ? n : 0), t.length - (1 == m.length ? n : 0)); u > o && s.charCodeAt(s.length - o - 1) == t.charCodeAt(t.length - o - 1);) ++o;
+            l[l.length - 1] = s.slice(0, s.length - o), l[0] = l[0].slice(n);
+            var v = oa(g, n),
+                w = oa(j, m.length ? bg(m)
+                    .length - o : 0);
+            return l.length > 1 || l[0] || pa(v, w) ? (nd(a.doc, l, v, w, "+input"), !0) : void 0
+        },
+        ensurePolled: function () {
+            this.forceCompositionEnd()
+        },
+        reset: function () {
+            this.forceCompositionEnd()
+        },
+        forceCompositionEnd: function () {
+            this.composing && !this.composing.handled && (this.applyComposition(this.composing), this.composing.handled = !0, this.div.blur(), this.div.focus())
+        },
+        applyComposition: function (a) {
+            a.data && a.data != a.startData && dc(this.cm, wa)(this.cm, a.data, 0, a.sel)
+        },
+        setUneditable: function (a) {
+            a.setAttribute("contenteditable", "false")
+        },
+        onKeyPress: function (a) {
+            a.preventDefault(), dc(this.cm, wa)(this.cm, String.fromCharCode(null == a.charCode ? a.keyCode : a.charCode), 0)
+        },
+        onContextMenu: fg,
+        resetPosition: fg,
+        needsContentAttribute: !0
+    }, Da.prototype), v.inputStyles = {
+        textarea: Ba,
+        contenteditable: Da
+    }, Ja.prototype = {
+        primary: function () {
+            return this.ranges[this.primIndex]
+        },
+        equals: function (a) {
+            if (a == this) return !0;
+            if (a.primIndex != this.primIndex || a.ranges.length != this.ranges.length) return !1;
+            for (var b = 0; b < this.ranges.length; b++) {
+                var c = this.ranges[b],
+                    d = a.ranges[b];
+                if (0 != pa(c.anchor, d.anchor) || 0 != pa(c.head, d.head)) return !1
+            }
+            return !0
+        },
+        deepCopy: function () {
+            for (var a = [], b = 0; b < this.ranges.length; b++) a[b] = new Ka(qa(this.ranges[b].anchor), qa(this.ranges[b].head));
+            return new Ja(a, this.primIndex)
+        },
+        somethingSelected: function () {
+            for (var a = 0; a < this.ranges.length; a++)
+                if (!this.ranges[a].empty()) return !0;
+            return !1
+        },
+        contains: function (a, b) {
+            b || (b = a);
+            for (var c = 0; c < this.ranges.length; c++) {
+                var d = this.ranges[c];
+                if (pa(b, d.from()) >= 0 && pa(a, d.to()) <= 0) return c
+            }
+            return -1
+        }
+    }, Ka.prototype = {
+        from: function () {
+            return sa(this.anchor, this.head)
+        },
+        to: function () {
+            return ra(this.anchor, this.head)
+        },
+        empty: function () {
+            return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch
+        }
+    };
+    var Qb, vc, wc, zb = {
+            left: 0,
+            right: 0,
+            top: 0,
+            bottom: 0
+        },
+        Tb = null,
+        Ub = 0,
+        Cc = 0,
+        Jc = 0,
+        Kc = null;
+    d ? Kc = -.53 : a ? Kc = 15 : h ? Kc = -.7 : j && (Kc = -1 / 3);
+    var Lc = function (a) {
+        var b = a.wheelDeltaX,
+            c = a.wheelDeltaY;
+        return null == b && a.detail && a.axis == a.HORIZONTAL_AXIS && (b = a.detail), null == c && a.detail && a.axis == a.VERTICAL_AXIS ? c = a.detail : null == c && (c = a.wheelDelta), {
+            x: b,
+            y: c
+        }
+    };
+    v.wheelEventPixels = function (a) {
+        var b = Lc(a);
+        return b.x *= Kc, b.y *= Kc, b
+    };
+    var Pc = new Yf,
+        Tc = null,
+        bd = v.changeEnd = function (a) {
+            return a.text ? oa(a.from.line + a.text.length - 1, bg(a.text)
+                .length + (1 == a.text.length ? a.from.ch : 0)) : a.to
+        };
+    v.prototype = {
+        constructor: v,
+        focus: function () {
+            window.focus(), this.display.input.focus()
+        },
+        setOption: function (a, b) {
+            var c = this.options,
+                d = c[a];
+            (c[a] != b || "mode" == a) && (c[a] = b, Bd.hasOwnProperty(a) && dc(this, Bd[a])(this, b, d))
+        },
+        getOption: function (a) {
+            return this.options[a]
+        },
+        getDoc: function () {
+            return this.doc
+        },
+        addKeyMap: function (a, b) {
+            this.state.keyMaps[b ? "push" : "unshift"](Rd(a))
+        },
+        removeKeyMap: function (a) {
+            for (var b = this.state.keyMaps, c = 0; c < b.length; ++c)
+                if (b[c] == a || b[c].name == a) return b.splice(c, 1), !0
+        },
+        addOverlay: ec(function (a, b) {
+            var c = a.token ? a : v.getMode(this.options, a);
+            if (c.startState) throw new Error("Overlays may not be stateful.");
+            this.state.overlays.push({
+                mode: c,
+                modeSpec: a,
+                opaque: b && b.opaque
+            }), this.state.modeGen++, ic(this)
+        }),
+        removeOverlay: ec(function (a) {
+            for (var b = this.state.overlays, c = 0; c < b.length; ++c) {
+                var d = b[c].modeSpec;
+                if (d == a || "string" == typeof a && d.name == a) return b.splice(c, 1), this.state.modeGen++, void ic(this)
+            }
+        }),
+        indentLine: ec(function (a, b, c) {
+            "string" != typeof b && "number" != typeof b && (b = null == b ? this.options.smartIndent ? "smart" : "prev" : b ? "add" : "subtract"), Qa(this.doc, a) && vd(this, a, b, c)
+        }),
+        indentSelection: ec(function (a) {
+            for (var b = this.doc.sel.ranges, c = -1, d = 0; d < b.length; d++) {
+                var e = b[d];
+                if (e.empty()) e.head.line > c && (vd(this, e.head.line, a, !0), c = e.head.line, d == this.doc.sel.primIndex && td(this));
+                else {
+                    var f = e.from(),
+                        g = e.to(),
+                        h = Math.max(c, f.line);
+                    c = Math.min(this.lastLine(), g.line - (g.ch ? 0 : 1)) + 1;
+                    for (var i = h; c > i; ++i) vd(this, i, a);
+                    var j = this.doc.sel.ranges;
+                    0 == f.ch && b.length == j.length && j[d].from()
+                        .ch > 0 && Va(this.doc, d, new Ka(f, j[d].to()), Vf)
+                }
+            }
+        }),
+        getTokenAt: function (a, b) {
+            return Ie(this, a, b)
+        },
+        getLineTokens: function (a, b) {
+            return Ie(this, oa(a), b, !0)
+        },
+        getTokenTypeAt: function (a) {
+            a = Oa(this.doc, a);
+            var f, b = Le(this, ff(this.doc, a.line)),
+                c = 0,
+                d = (b.length - 1) / 2,
+                e = a.ch;
+            if (0 == e) f = b[2];
+            else
+                for (;;) {
+                    var g = c + d >> 1;
+                    if ((g ? b[2 * g - 1] : 0) >= e) d = g;
+                    else {
+                        if (!(b[2 * g + 1] < e)) {
+                            f = b[2 * g + 2];
+                            break
+                        }
+                        c = g + 1
+                    }
+                }
+            var h = f ? f.indexOf("cm-overlay ") : -1;
+            return 0 > h ? f : 0 == h ? null : f.slice(0, h - 1)
+        },
+        getModeAt: function (a) {
+            var b = this.doc.mode;
+            return b.innerMode ? v.innerMode(b, this.getTokenAt(a)
+                    .state)
+                .mode : b
+        },
+        getHelper: function (a, b) {
+            return this.getHelpers(a, b)[0]
+        },
+        getHelpers: function (a, b) {
+            var c = [];
+            if (!Id.hasOwnProperty(b)) return c;
+            var d = Id[b],
+                e = this.getModeAt(a);
+            if ("string" == typeof e[b]) d[e[b]] && c.push(d[e[b]]);
+            else if (e[b])
+                for (var f = 0; f < e[b].length; f++) {
+                    var g = d[e[b][f]];
+                    g && c.push(g)
+                } else e.helperType && d[e.helperType] ? c.push(d[e.helperType]) : d[e.name] && c.push(d[e.name]);
+            for (var f = 0; f < d._global.length; f++) {
+                var h = d._global[f];
+                h.pred(e, this) && -1 == dg(c, h.val) && c.push(h.val)
+            }
+            return c
+        },
+        getStateAfter: function (a, b) {
+            var c = this.doc;
+            return a = Na(c, null == a ? c.first + c.size - 1 : a), lb(this, a + 1, b)
+        },
+        cursorCoords: function (a, b) {
+            var c, d = this.doc.sel.primary();
+            return c = null == a ? d.head : "object" == typeof a ? Oa(this.doc, a) : a ? d.from() : d.to(), Lb(this, c, b || "page")
+        },
+        charCoords: function (a, b) {
+            return Kb(this, Oa(this.doc, a), b || "page")
+        },
+        coordsChar: function (a, b) {
+            return a = Jb(this, a, b || "page"), Ob(this, a.left, a.top)
+        },
+        lineAtHeight: function (a, b) {
+            return a = Jb(this, {
+                    top: a,
+                    left: 0
+                }, b || "page")
+                .top, lf(this.doc, a + this.display.viewOffset)
+        },
+        heightAtLine: function (a, b) {
+            var d, c = !1;
+            if ("number" == typeof a) {
+                var e = this.doc.first + this.doc.size - 1;
+                a < this.doc.first ? a = this.doc.first : a > e && (a = e, c = !0), d = ff(this.doc, a)
+            } else d = a;
+            return Ib(this, d, {
+                    top: 0,
+                    left: 0
+                }, b || "page")
+                .top + (c ? this.doc.height - mf(d) : 0)
+        },
+        defaultTextHeight: function () {
+            return Rb(this.display)
+        },
+        defaultCharWidth: function () {
+            return Sb(this.display)
+        },
+        setGutterMarker: ec(function (a, b, c) {
+            return wd(this.doc, a, "gutter", function (a) {
+                var d = a.gutterMarkers || (a.gutterMarkers = {});
+                return d[b] = c, !c && mg(d) && (a.gutterMarkers = null), !0
+            })
+        }),
+        clearGutter: ec(function (a) {
+            var b = this,
+                c = b.doc,
+                d = c.first;
+            c.iter(function (c) {
+                c.gutterMarkers && c.gutterMarkers[a] && (c.gutterMarkers[a] = null, jc(b, d, "gutter"), mg(c.gutterMarkers) && (c.gutterMarkers = null)), ++d
+            })
+        }),
+        lineInfo: function (a) {
+            if ("number" == typeof a) {
+                if (!Qa(this.doc, a)) return null;
+                var b = a;
+                if (a = ff(this.doc, a), !a) return null
+            } else {
+                var b = kf(a);
+                if (null == b) return null
+            }
+            return {
+                line: b,
+                handle: a,
+                text: a.text,
+                gutterMarkers: a.gutterMarkers,
+                textClass: a.textClass,
+                bgClass: a.bgClass,
+                wrapClass: a.wrapClass,
+                widgets: a.widgets
+            }
+        },
+        getViewport: function () {
+            return {
+                from: this.display.viewFrom,
+                to: this.display.viewTo
+            }
+        },
+        addWidget: function (a, b, c, d, e) {
+            var f = this.display;
+            a = Lb(this, Oa(this.doc, a));
+            var g = a.bottom,
+                h = a.left;
+            if (b.style.position = "absolute", b.setAttribute("cm-ignore-events", "true"), this.display.input.setUneditable(b), f.sizer.appendChild(b), "over" == d) g = a.top;
+            else if ("above" == d || "near" == d) {
+                var i = Math.max(f.wrapper.clientHeight, this.doc.height),
+                    j = Math.max(f.sizer.clientWidth, f.lineSpace.clientWidth);
+                ("above" == d || a.bottom + b.offsetHeight > i) && a.top > b.offsetHeight ? g = a.top - b.offsetHeight : a.bottom + b.offsetHeight <= i && (g = a.bottom), h + b.offsetWidth > j && (h = j - b.offsetWidth)
+            }
+            b.style.top = g + "px", b.style.left = b.style.right = "", "right" == e ? (h = f.sizer.clientWidth - b.offsetWidth, b.style.right = "0px") : ("left" == e ? h = 0 : "middle" == e && (h = (f.sizer.clientWidth - b.offsetWidth) / 2), b.style.left = h + "px"), c && qd(this, h, g, h + b.offsetWidth, g + b.offsetHeight)
+        },
+        triggerOnKeyDown: ec(Uc),
+        triggerOnKeyPress: ec(Xc),
+        triggerOnKeyUp: Wc,
+        execCommand: function (a) {
+            return Ld.hasOwnProperty(a) ? Ld[a].call(null, this) : void 0
+        },
+        triggerElectric: ec(function (a) {
+            ya(this, a)
+        }),
+        findPosH: function (a, b, c, d) {
+            var e = 1;
+            0 > b && (e = -1, b = -b);
+            for (var f = 0, g = Oa(this.doc, a); b > f && (g = yd(this.doc, g, e, c, d), !g.hitSide); ++f);
+            return g
+        },
+        moveH: ec(function (a, b) {
+            var c = this;
+            c.extendSelectionsBy(function (d) {
+                return c.display.shift || c.doc.extend || d.empty() ? yd(c.doc, d.head, a, b, c.options.rtlMoveVisually) : 0 > a ? d.from() : d.to()
+            }, Xf)
+        }),
+        deleteH: ec(function (a, b) {
+            var c = this.doc.sel,
+                d = this.doc;
+            c.somethingSelected() ? d.replaceSelection("", null, "+delete") : xd(this, function (c) {
+                var e = yd(d, c.head, a, b, !1);
+                return 0 > a ? {
+                    from: e,
+                    to: c.head
+                } : {
+                    from: c.head,
+                    to: e
+                }
+            })
+        }),
+        findPosV: function (a, b, c, d) {
+            var e = 1,
+                f = d;
+            0 > b && (e = -1, b = -b);
+            for (var g = 0, h = Oa(this.doc, a); b > g; ++g) {
+                var i = Lb(this, h, "div");
+                if (null == f ? f = i.left : i.left = f, h = zd(this, i, e, c), h.hitSide) break
+            }
+            return h
+        },
+        moveV: ec(function (a, b) {
+            var c = this,
+                d = this.doc,
+                e = [],
+                f = !c.display.shift && !d.extend && d.sel.somethingSelected();
+            if (d.extendSelectionsBy(function (g) {
+                    if (f) return 0 > a ? g.from() : g.to();
+                    var h = Lb(c, g.head, "div");
+                    null != g.goalColumn && (h.left = g.goalColumn), e.push(h.left);
+                    var i = zd(c, h, a, b);
+                    return "page" == b && g == d.sel.primary() && sd(c, null, Kb(c, i, "div")
+                        .top - h.top), i
+                }, Xf), e.length)
+                for (var g = 0; g < d.sel.ranges.length; g++) d.sel.ranges[g].goalColumn = e[g]
+        }),
+        findWordAt: function (a) {
+            var b = this.doc,
+                c = ff(b, a.line)
+                .text,
+                d = a.ch,
+                e = a.ch;
+            if (c) {
+                var f = this.getHelper(a, "wordChars");
+                (a.xRel < 0 || e == c.length) && d ? --d : ++e;
+                for (var g = c.charAt(d), h = lg(g, f) ? function (a) {
+                        return lg(a, f)
+                    } : /\s/.test(g) ? function (a) {
+                        return /\s/.test(a)
+                    } : function (a) {
+                        return !/\s/.test(a) && !lg(a)
+                    }; d > 0 && h(c.charAt(d - 1));) --d;
+                for (; e < c.length && h(c.charAt(e));) ++e
+            }
+            return new Ka(oa(a.line, d), oa(a.line, e))
+        },
+        toggleOverwrite: function (a) {
+            (null == a || a != this.state.overwrite) && ((this.state.overwrite = !this.state.overwrite) ? xg(this.display.cursorDiv, "CodeMirror-overwrite") : wg(this.display.cursorDiv, "CodeMirror-overwrite"), Lf(this, "overwriteToggle", this, this.state.overwrite))
+        },
+        hasFocus: function () {
+            return this.display.input.getField() == ug()
+        },
+        scrollTo: ec(function (a, b) {
+            (null != a || null != b) && ud(this), null != a && (this.curOp.scrollLeft = a), null != b && (this.curOp.scrollTop = b)
+        }),
+        getScrollInfo: function () {
+            var a = this.display.scroller;
+            return {
+                left: a.scrollLeft,
+                top: a.scrollTop,
+                height: a.scrollHeight - pb(this) - this.display.barHeight,
+                width: a.scrollWidth - pb(this) - this.display.barWidth,
+                clientHeight: rb(this),
+                clientWidth: qb(this)
+            }
+        },
+        scrollIntoView: ec(function (a, b) {
+            if (null == a ? (a = {
+                    from: this.doc.sel.primary()
+                        .head,
+                    to: null
+                }, null == b && (b = this.options.cursorScrollMargin)) : "number" == typeof a ? a = {
+                    from: oa(a, 0),
+                    to: null
+                } : null == a.from && (a = {
+                    from: a,
+                    to: null
+                }), a.to || (a.to = a.from), a.margin = b || 0, null != a.from.line) ud(this), this.curOp.scrollToPos = a;
+            else {
+                var c = rd(this, Math.min(a.from.left, a.to.left), Math.min(a.from.top, a.to.top) - a.margin, Math.max(a.from.right, a.to.right), Math.max(a.from.bottom, a.to.bottom) + a.margin);
+                this.scrollTo(c.scrollLeft, c.scrollTop)
+            }
+        }),
+        setSize: ec(function (a, b) {
+            function d(a) {
+                return "number" == typeof a || /^\d+$/.test(String(a)) ? a + "px" : a
+            }
+            var c = this;
+            null != a && (c.display.wrapper.style.width = d(a)), null != b && (c.display.wrapper.style.height = d(b)), c.options.lineWrapping && Eb(this);
+            var e = c.display.viewFrom;
+            c.doc.iter(e, c.display.viewTo, function (a) {
+                if (a.widgets)
+                    for (var b = 0; b < a.widgets.length; b++)
+                        if (a.widgets[b].noHScroll) {
+                            jc(c, e, "widget");
+                            break
+                        }++e
+            }), c.curOp.forceUpdate = !0, Lf(c, "refresh", this)
+        }),
+        operation: function (a) {
+            return cc(this, a)
+        },
+        refresh: ec(function () {
+            var a = this.display.cachedTextHeight;
+            ic(this), this.curOp.forceUpdate = !0, Fb(this), this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop), F(this), (null == a || Math.abs(a - Rb(this.display)) > .5) && B(this), Lf(this, "refresh", this)
+        }),
+        swapDoc: ec(function (a) {
+            var b = this.doc;
+            return b.cm = null, ef(this, a), Fb(this), this.display.input.reset(), this.scrollTo(a.scrollLeft, a.scrollTop), this.curOp.forceScroll = !0, Nf(this, "swapDoc", this, b), b
+        }),
+        getInputField: function () {
+            return this.display.input.getField()
+        },
+        getWrapperElement: function () {
+            return this.display.wrapper
+        },
+        getScrollerElement: function () {
+            return this.display.scroller
+        },
+        getGutterElement: function () {
+            return this.display.gutters
+        }
+    }, Sf(v);
+    var Ad = v.defaults = {},
+        Bd = v.optionHandlers = {},
+        Dd = v.Init = {
+            toString: function () {
+                return "CodeMirror.Init"
+            }
+        };
+    Cd("value", "", function (a, b) {
+        a.setValue(b)
+    }, !0), Cd("mode", null, function (a, b) {
+        a.doc.modeOption = b, x(a)
+    }, !0), Cd("indentUnit", 2, x, !0), Cd("indentWithTabs", !1), Cd("smartIndent", !0), Cd("tabSize", 4, function (a) {
+        y(a), Fb(a), ic(a)
+    }, !0), Cd("lineSeparator", null, function (a, b) {
+        if (a.doc.lineSep = b, b) {
+            var c = [],
+                d = a.doc.first;
+            a.doc.iter(function (a) {
+                for (var e = 0;;) {
+                    var f = a.text.indexOf(b, e);
+                    if (-1 == f) break;
+                    e = f + b.length, c.push(oa(d, f))
+                }
+                d++
+            });
+            for (var e = c.length - 1; e >= 0; e--) nd(a.doc, b, c[e], oa(c[e].line, c[e].ch + b.length))
+        }
+    }), Cd("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function (a, b, c) {
+        a.state.specialChars = new RegExp(b.source + (b.test("	") ? "" : "|	"), "g"), c != v.Init && a.refresh()
+    }), Cd("specialCharPlaceholder", Re, function (a) {
+        a.refresh()
+    }, !0), Cd("electricChars", !0), Cd("inputStyle", n ? "contenteditable" : "textarea", function () {
+        throw new Error("inputStyle can not (yet) be changed in a running editor")
+    }, !0), Cd("rtlMoveVisually", !p), Cd("wholeLineUpdateBefore", !0), Cd("theme", "default", function (a) {
+        C(a), D(a)
+    }, !0), Cd("keyMap", "default", function (a, b, c) {
+        var d = Rd(b),
+            e = c != v.Init && Rd(c);
+        e && e.detach && e.detach(a, d), d.attach && d.attach(a, e || null)
+    }), Cd("extraKeys", null), Cd("lineWrapping", !1, z, !0), Cd("gutters", [], function (a) {
+        I(a.options), D(a)
+    }, !0), Cd("fixedGutter", !0, function (a, b) {
+        a.display.gutters.style.left = b ? T(a.display) + "px" : "0", a.refresh()
+    }, !0), Cd("coverGutterNextToScrollbar", !1, function (a) {
+        N(a)
+    }, !0), Cd("scrollbarStyle", "native", function (a) {
+        M(a), N(a), a.display.scrollbars.setScrollTop(a.doc.scrollTop), a.display.scrollbars.setScrollLeft(a.doc.scrollLeft)
+    }, !0), Cd("lineNumbers", !1, function (a) {
+        I(a.options), D(a)
+    }, !0), Cd("firstLineNumber", 1, D, !0), Cd("lineNumberFormatter", function (a) {
+        return a
+    }, D, !0), Cd("showCursorWhenSelecting", !1, db, !0), Cd("resetSelectionOnContextMenu", !0), Cd("lineWiseCopyCut", !0), Cd("readOnly", !1, function (a, b) {
+        "nocursor" == b ? ($c(a), a.display.input.blur(), a.display.disabled = !0) : (a.display.disabled = !1, b || a.display.input.reset())
+    }), Cd("disableInput", !1, function (a, b) {
+        b || a.display.input.reset()
+    }, !0), Cd("dragDrop", !0, qc), Cd("cursorBlinkRate", 530), Cd("cursorScrollMargin", 0), Cd("cursorHeight", 1, db, !0), Cd("singleCursorHeightPerLine", !0, db, !0), Cd("workTime", 100), Cd("workDelay", 100), Cd("flattenSpans", !0, y, !0), Cd("addModeClass", !1, y, !0), Cd("pollInterval", 100), Cd("undoDepth", 200, function (a, b) {
+        a.doc.history.undoDepth = b
+    }), Cd("historyEventDelay", 1250), Cd("viewportMargin", 10, function (a) {
+        a.refresh()
+    }, !0), Cd("maxHighlightLength", 1e4, y, !0), Cd("moveInputWithCursor", !0, function (a, b) {
+        b || a.display.input.resetPosition()
+    }), Cd("tabindex", null, function (a, b) {
+        a.display.input.getField()
+            .tabIndex = b || ""
+    }), Cd("autofocus", null);
+    var Ed = v.modes = {},
+        Fd = v.mimeModes = {};
+    v.defineMode = function (a, b) {
+        v.defaults.mode || "null" == a || (v.defaults.mode = a), arguments.length > 2 && (b.dependencies = Array.prototype.slice.call(arguments, 2)), Ed[a] = b
+    }, v.defineMIME = function (a, b) {
+        Fd[a] = b
+    }, v.resolveMode = function (a) {
+        if ("string" == typeof a && Fd.hasOwnProperty(a)) a = Fd[a];
+        else if (a && "string" == typeof a.name && Fd.hasOwnProperty(a.name)) {
+            var b = Fd[a.name];
+            "string" == typeof b && (b = {
+                name: b
+            }), a = gg(b, a), a.name = b.name
+        } else if ("string" == typeof a && /^[\w\-]+\/[\w\-]+\+xml$/.test(a)) return v.resolveMode("application/xml");
+        return "string" == typeof a ? {
+            name: a
+        } : a || {
+            name: "null"
+        }
+    }, v.getMode = function (a, b) {
+        var b = v.resolveMode(b),
+            c = Ed[b.name];
+        if (!c) return v.getMode(a, "text/plain");
+        var d = c(a, b);
+        if (Gd.hasOwnProperty(b.name)) {
+            var e = Gd[b.name];
+            for (var f in e) e.hasOwnProperty(f) && (d.hasOwnProperty(f) && (d["_" + f] = d[f]), d[f] = e[f])
+        }
+        if (d.name = b.name, b.helperType && (d.helperType = b.helperType), b.modeProps)
+            for (var f in b.modeProps) d[f] = b.modeProps[f];
+        return d
+    }, v.defineMode("null", function () {
+        return {
+            token: function (a) {
+                a.skipToEnd()
+            }
+        }
+    }), v.defineMIME("text/plain", "null");
+    var Gd = v.modeExtensions = {};
+    v.extendMode = function (a, b) {
+        var c = Gd.hasOwnProperty(a) ? Gd[a] : Gd[a] = {};
+        hg(b, c)
+    }, v.defineExtension = function (a, b) {
+        v.prototype[a] = b
+    }, v.defineDocExtension = function (a, b) {
+        af.prototype[a] = b
+    }, v.defineOption = Cd;
+    var Hd = [];
+    v.defineInitHook = function (a) {
+        Hd.push(a)
+    };
+    var Id = v.helpers = {};
+    v.registerHelper = function (a, b, c) {
+        Id.hasOwnProperty(a) || (Id[a] = v[a] = {
+            _global: []
+        }), Id[a][b] = c
+    }, v.registerGlobalHelper = function (a, b, c, d) {
+        v.registerHelper(a, b, d), Id[a]._global.push({
+            pred: c,
+            val: d
+        })
+    };
+    var Jd = v.copyState = function (a, b) {
+            if (b === !0) return b;
+            if (a.copyState) return a.copyState(b);
+            var c = {};
+            for (var d in b) {
+                var e = b[d];
+                e instanceof Array && (e = e.concat([])), c[d] = e
+            }
+            return c
+        },
+        Kd = v.startState = function (a, b, c) {
+            return a.startState ? a.startState(b, c) : !0
+        };
+    v.innerMode = function (a, b) {
+        for (; a.innerMode;) {
+            var c = a.innerMode(b);
+            if (!c || c.mode == a) break;
+            b = c.state, a = c.mode
+        }
+        return c || {
+            mode: a,
+            state: b
+        }
+    };
+    var Ld = v.commands = {
+            selectAll: function (a) {
+                a.setSelection(oa(a.firstLine(), 0), oa(a.lastLine()), Vf)
+            },
+            singleSelection: function (a) {
+                a.setSelection(a.getCursor("anchor"), a.getCursor("head"), Vf)
+            },
+            killLine: function (a) {
+                xd(a, function (b) {
+                    if (b.empty()) {
+                        var c = ff(a.doc, b.head.line)
+                            .text.length;
+                        return b.head.ch == c && b.head.line < a.lastLine() ? {
+                            from: b.head,
+                            to: oa(b.head.line + 1, 0)
+                        } : {
+                            from: b.head,
+                            to: oa(b.head.line, c)
+                        }
+                    }
+                    return {
+                        from: b.from(),
+                        to: b.to()
+                    }
+                })
+            },
+            deleteLine: function (a) {
+                xd(a, function (b) {
+                    return {
+                        from: oa(b.from()
+                            .line, 0),
+                        to: Oa(a.doc, oa(b.to()
+                            .line + 1, 0))
+                    }
+                })
+            },
+            delLineLeft: function (a) {
+                xd(a, function (a) {
+                    return {
+                        from: oa(a.from()
+                            .line, 0),
+                        to: a.from()
+                    }
+                })
+            },
+            delWrappedLineLeft: function (a) {
+                xd(a, function (b) {
+                    var c = a.charCoords(b.head, "div")
+                        .top + 5,
+                        d = a.coordsChar({
+                            left: 0,
+                            top: c
+                        }, "div");
+                    return {
+                        from: d,
+                        to: b.from()
+                    }
+                })
+            },
+            delWrappedLineRight: function (a) {
+                xd(a, function (b) {
+                    var c = a.charCoords(b.head, "div")
+                        .top + 5,
+                        d = a.coordsChar({
+                            left: a.display.lineDiv.offsetWidth + 100,
+                            top: c
+                        }, "div");
+                    return {
+                        from: b.from(),
+                        to: d
+                    }
+                })
+            },
+            undo: function (a) {
+                a.undo()
+            },
+            redo: function (a) {
+                a.redo()
+            },
+            undoSelection: function (a) {
+                a.undoSelection()
+            },
+            redoSelection: function (a) {
+                a.redoSelection()
+            },
+            goDocStart: function (a) {
+                a.extendSelection(oa(a.firstLine(), 0))
+            },
+            goDocEnd: function (a) {
+                a.extendSelection(oa(a.lastLine()))
+            },
+            goLineStart: function (a) {
+                a.extendSelectionsBy(function (b) {
+                    return Tg(a, b.head.line)
+                }, {
+                    origin: "+move",
+                    bias: 1
+                })
+            },
+            goLineStartSmart: function (a) {
+                a.extendSelectionsBy(function (b) {
+                    return Vg(a, b.head)
+                }, {
+                    origin: "+move",
+                    bias: 1
+                })
+            },
+            goLineEnd: function (a) {
+                a.extendSelectionsBy(function (b) {
+                    return Ug(a, b.head.line)
+                }, {
+                    origin: "+move",
+                    bias: -1
+                })
+            },
+            goLineRight: function (a) {
+                a.extendSelectionsBy(function (b) {
+                    var c = a.charCoords(b.head, "div")
+                        .top + 5;
+                    return a.coordsChar({
+                        left: a.display.lineDiv.offsetWidth + 100,
+                        top: c
+                    }, "div")
+                }, Xf)
+            },
+            goLineLeft: function (a) {
+                a.extendSelectionsBy(function (b) {
+                    var c = a.charCoords(b.head, "div")
+                        .top + 5;
+                    return a.coordsChar({
+                        left: 0,
+                        top: c
+                    }, "div")
+                }, Xf)
+            },
+            goLineLeftSmart: function (a) {
+                a.extendSelectionsBy(function (b) {
+                    var c = a.charCoords(b.head, "div")
+                        .top + 5,
+                        d = a.coordsChar({
+                            left: 0,
+                            top: c
+                        }, "div");
+                    return d.ch < a.getLine(d.line)
+                        .search(/\S/) ? Vg(a, b.head) : d
+                }, Xf)
+            },
+            goLineUp: function (a) {
+                a.moveV(-1, "line")
+            },
+            goLineDown: function (a) {
+                a.moveV(1, "line")
+            },
+            goPageUp: function (a) {
+                a.moveV(-1, "page")
+            },
+            goPageDown: function (a) {
+                a.moveV(1, "page")
+            },
+            goCharLeft: function (a) {
+                a.moveH(-1, "char")
+            },
+            goCharRight: function (a) {
+                a.moveH(1, "char")
+            },
+            goColumnLeft: function (a) {
+                a.moveH(-1, "column")
+            },
+            goColumnRight: function (a) {
+                a.moveH(1, "column")
+            },
+            goWordLeft: function (a) {
+                a.moveH(-1, "word")
+            },
+            goGroupRight: function (a) {
+                a.moveH(1, "group")
+            },
+            goGroupLeft: function (a) {
+                a.moveH(-1, "group")
+            },
+            goWordRight: function (a) {
+                a.moveH(1, "word")
+            },
+            delCharBefore: function (a) {
+                a.deleteH(-1, "char")
+            },
+            delCharAfter: function (a) {
+                a.deleteH(1, "char")
+            },
+            delWordBefore: function (a) {
+                a.deleteH(-1, "word")
+            },
+            delWordAfter: function (a) {
+                a.deleteH(1, "word")
+            },
+            delGroupBefore: function (a) {
+                a.deleteH(-1, "group")
+            },
+            delGroupAfter: function (a) {
+                a.deleteH(1, "group")
+            },
+            indentAuto: function (a) {
+                a.indentSelection("smart")
+            },
+            indentMore: function (a) {
+                a.indentSelection("add")
+            },
+            indentLess: function (a) {
+                a.indentSelection("subtract")
+            },
+            insertTab: function (a) {
+                a.replaceSelection("	")
+            },
+            insertSoftTab: function (a) {
+                for (var b = [], c = a.listSelections(), d = a.options.tabSize, e = 0; e < c.length; e++) {
+                    var f = c[e].from(),
+                        g = Zf(a.getLine(f.line), f.ch, d);
+                    b.push(new Array(d - g % d + 1)
+                        .join(" "))
+                }
+                a.replaceSelections(b)
+            },
+            defaultTab: function (a) {
+                a.somethingSelected() ? a.indentSelection("add") : a.execCommand("insertTab")
+            },
+            transposeChars: function (a) {
+                cc(a, function () {
+                    for (var b = a.listSelections(), c = [], d = 0; d < b.length; d++) {
+                        var e = b[d].head,
+                            f = ff(a.doc, e.line)
+                            .text;
+                        if (f)
+                            if (e.ch == f.length && (e = new oa(e.line, e.ch - 1)), e.ch > 0) e = new oa(e.line, e.ch + 1), a.replaceRange(f.charAt(e.ch - 1) + f.charAt(e.ch - 2), oa(e.line, e.ch - 2), e, "+transpose");
+                            else if (e.line > a.doc.first) {
+                            var g = ff(a.doc, e.line - 1)
+                                .text;
+                            g && a.replaceRange(f.charAt(0) + a.doc.lineSeparator() + g.charAt(g.length - 1), oa(e.line - 1, g.length - 1), oa(e.line, 1), "+transpose")
+                        }
+                        c.push(new Ka(e, e))
+                    }
+                    a.setSelections(c)
+                })
+            },
+            newlineAndIndent: function (a) {
+                cc(a, function () {
+                    for (var b = a.listSelections()
+                            .length, c = 0; b > c; c++) {
+                        var d = a.listSelections()[c];
+                        a.replaceRange(a.doc.lineSeparator(), d.anchor, d.head, "+input"), a.indentLine(d.from()
+                            .line + 1, null, !0), td(a)
+                    }
+                })
+            },
+            toggleOverwrite: function (a) {
+                a.toggleOverwrite()
+            }
+        },
+        Md = v.keyMap = {};
+    Md.basic = {
+        Left: "goCharLeft",
+        Right: "goCharRight",
+        Up: "goLineUp",
+        Down: "goLineDown",
+        End: "goLineEnd",
+        Home: "goLineStartSmart",
+        PageUp: "goPageUp",
+        PageDown: "goPageDown",
+        Delete: "delCharAfter",
+        Backspace: "delCharBefore",
+        "Shift-Backspace": "delCharBefore",
+        Tab: "defaultTab",
+        "Shift-Tab": "indentAuto",
+        Enter: "newlineAndIndent",
+        Insert: "toggleOverwrite",
+        Esc: "singleSelection"
+    }, Md.pcDefault = {
+        "Ctrl-A": "selectAll",
+        "Ctrl-D": "deleteLine",
+        "Ctrl-Z": "undo",
+        "Shift-Ctrl-Z": "redo",
+        "Ctrl-Y": "redo",
+        "Ctrl-Home": "goDocStart",
+        "Ctrl-End": "goDocEnd",
+        "Ctrl-Up": "goLineUp",
+        "Ctrl-Down": "goLineDown",
+        "Ctrl-Left": "goGroupLeft",
+        "Ctrl-Right": "goGroupRight",
+        "Alt-Left": "goLineStart",
+        "Alt-Right": "goLineEnd",
+        "Ctrl-Backspace": "delGroupBefore",
+        "Ctrl-Delete": "delGroupAfter",
+        "Ctrl-S": "save",
+        "Ctrl-F": "find",
+        "Ctrl-G": "findNext",
+        "Shift-Ctrl-G": "findPrev",
+        "Shift-Ctrl-F": "replace",
+        "Shift-Ctrl-R": "replaceAll",
+        "Ctrl-[": "indentLess",
+        "Ctrl-]": "indentMore",
+        "Ctrl-U": "undoSelection",
+        "Shift-Ctrl-U": "redoSelection",
+        "Alt-U": "redoSelection",
+        fallthrough: "basic"
+    }, Md.emacsy = {
+        "Ctrl-F": "goCharRight",
+        "Ctrl-B": "goCharLeft",
+        "Ctrl-P": "goLineUp",
+        "Ctrl-N": "goLineDown",
+        "Alt-F": "goWordRight",
+        "Alt-B": "goWordLeft",
+        "Ctrl-A": "goLineStart",
+        "Ctrl-E": "goLineEnd",
+        "Ctrl-V": "goPageDown",
+        "Shift-Ctrl-V": "goPageUp",
+        "Ctrl-D": "delCharAfter",
+        "Ctrl-H": "delCharBefore",
+        "Alt-D": "delWordAfter",
+        "Alt-Backspace": "delWordBefore",
+        "Ctrl-K": "killLine",
+        "Ctrl-T": "transposeChars"
+    }, Md.macDefault = {
+        "Cmd-A": "selectAll",
+        "Cmd-D": "deleteLine",
+        "Cmd-Z": "undo",
+        "Shift-Cmd-Z": "redo",
+        "Cmd-Y": "redo",
+        "Cmd-Home": "goDocStart",
+        "Cmd-Up": "goDocStart",
+        "Cmd-End": "goDocEnd",
+        "Cmd-Down": "goDocEnd",
+        "Alt-Left": "goGroupLeft",
+        "Alt-Right": "goGroupRight",
+        "Cmd-Left": "goLineLeft",
+        "Cmd-Right": "goLineRight",
+        "Alt-Backspace": "delGroupBefore",
+        "Ctrl-Alt-Backspace": "delGroupAfter",
+        "Alt-Delete": "delGroupAfter",
+        "Cmd-S": "save",
+        "Cmd-F": "find",
+        "Cmd-G": "findNext",
+        "Shift-Cmd-G": "findPrev",
+        "Cmd-Alt-F": "replace",
+        "Shift-Cmd-Alt-F": "replaceAll",
+        "Cmd-[": "indentLess",
+        "Cmd-]": "indentMore",
+        "Cmd-Backspace": "delWrappedLineLeft",
+        "Cmd-Delete": "delWrappedLineRight",
+        "Cmd-U": "undoSelection",
+        "Shift-Cmd-U": "redoSelection",
+        "Ctrl-Up": "goDocStart",
+        "Ctrl-Down": "goDocEnd",
+        fallthrough: ["basic", "emacsy"]
+    }, Md["default"] = o ? Md.macDefault : Md.pcDefault, v.normalizeKeyMap = function (a) {
+        var b = {};
+        for (var c in a)
+            if (a.hasOwnProperty(c)) {
+                var d = a[c];
+                if (/^(name|fallthrough|(de|at)tach)$/.test(c)) continue;
+                if ("..." == d) {
+                    delete a[c];
+                    continue
+                }
+                for (var e = eg(c.split(" "), Nd), f = 0; f < e.length; f++) {
+                    var g, h;
+                    f == e.length - 1 ? (h = e.join(" "), g = d) : (h = e.slice(0, f + 1)
+                        .join(" "), g = "...");
+                    var i = b[h];
+                    if (i) {
+                        if (i != g) throw new Error("Inconsistent bindings for " + h)
+                    } else b[h] = g
+                }
+                delete a[c]
+            }
+        for (var j in b) a[j] = b[j];
+        return a
+    };
+    var Od = v.lookupKey = function (a, b, c, d) {
+            b = Rd(b);
+            var e = b.call ? b.call(a, d) : b[a];
+            if (e === !1) return "nothing";
+            if ("..." === e) return "multi";
+            if (null != e && c(e)) return "handled";
+            if (b.fallthrough) {
+                if ("[object Array]" != Object.prototype.toString.call(b.fallthrough)) return Od(a, b.fallthrough, c, d);
+                for (var f = 0; f < b.fallthrough.length; f++) {
+                    var g = Od(a, b.fallthrough[f], c, d);
+                    if (g) return g
+                }
+            }
+        },
+        Pd = v.isModifierKey = function (a) {
+            var b = "string" == typeof a ? a : Ng[a.keyCode];
+            return "Ctrl" == b || "Alt" == b || "Shift" == b || "Mod" == b
+        },
+        Qd = v.keyName = function (a, b) {
+            if (i && 34 == a.keyCode && a["char"]) return !1;
+            var c = Ng[a.keyCode],
+                d = c;
+            return null == d || a.altGraphKey ? !1 : (a.altKey && "Alt" != c && (d = "Alt-" + d), (r ? a.metaKey : a.ctrlKey) && "Ctrl" != c && (d = "Ctrl-" + d), (r ? a.ctrlKey : a.metaKey) && "Cmd" != c && (d = "Cmd-" + d), !b && a.shiftKey && "Shift" != c && (d = "Shift-" + d), d)
+        };
+    v.fromTextArea = function (a, b) {
+        function d() {
+            a.value = i.getValue()
+        }
+        if (b = b ? hg(b) : {}, b.value = a.value, !b.tabindex && a.tabIndex && (b.tabindex = a.tabIndex), !b.placeholder && a.placeholder && (b.placeholder = a.placeholder), null == b.autofocus) {
+            var c = ug();
+            b.autofocus = c == a || null != a.getAttribute("autofocus") && c == document.body
+        }
+        if (a.form && (Jf(a.form, "submit", d), !b.leaveSubmitMethodAlone)) {
+            var e = a.form,
+                f = e.submit;
+            try {
+                var g = e.submit = function () {
+                    d(), e.submit = f, e.submit(), e.submit = g
+                }
+            } catch (h) {}
+        }
+        b.finishInit = function (b) {
+            b.save = d, b.getTextArea = function () {
+                return a
+            }, b.toTextArea = function () {
+                b.toTextArea = isNaN, d(), a.parentNode.removeChild(b.getWrapperElement()), a.style.display = "", a.form && (Kf(a.form, "submit", d), "function" == typeof a.form.submit && (a.form.submit = f))
+            }
+        }, a.style.display = "none";
+        var i = v(function (b) {
+            a.parentNode.insertBefore(b, a.nextSibling)
+        }, b);
+        return i
+    };
+    var Sd = v.StringStream = function (a, b) {
+        this.pos = this.start = 0, this.string = a, this.tabSize = b || 8, this.lastColumnPos = this.lastColumnValue = 0, this.lineStart = 0
+    };
+    Sd.prototype = {
+        eol: function () {
+            return this.pos >= this.string.length
+        },
+        sol: function () {
+            return this.pos == this.lineStart
+        },
+        peek: function () {
+            return this.string.charAt(this.pos) || void 0
+        },
+        next: function () {
+            return this.pos < this.string.length ? this.string.charAt(this.pos++) : void 0
+        },
+        eat: function (a) {
+            var b = this.string.charAt(this.pos);
+            if ("string" == typeof a) var c = b == a;
+            else var c = b && (a.test ? a.test(b) : a(b));
+            return c ? (++this.pos, b) : void 0
+        },
+        eatWhile: function (a) {
+            for (var b = this.pos; this.eat(a););
+            return this.pos > b
+        },
+        eatSpace: function () {
+            for (var a = this.pos;
+                /[\s\u00a0]/.test(this.string.charAt(this.pos));) ++this.pos;
+            return this.pos > a
+        },
+        skipToEnd: function () {
+            this.pos = this.string.length
+        },
+        skipTo: function (a) {
+            var b = this.string.indexOf(a, this.pos);
+            return b > -1 ? (this.pos = b, !0) : void 0
+        },
+        backUp: function (a) {
+            this.pos -= a
+        },
+        column: function () {
+            return this.lastColumnPos < this.start && (this.lastColumnValue = Zf(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue), this.lastColumnPos = this.start), this.lastColumnValue - (this.lineStart ? Zf(this.string, this.lineStart, this.tabSize) : 0)
+        },
+        indentation: function () {
+            return Zf(this.string, null, this.tabSize) - (this.lineStart ? Zf(this.string, this.lineStart, this.tabSize) : 0)
+        },
+        match: function (a, b, c) {
+            if ("string" != typeof a) {
+                var f = this.string.slice(this.pos)
+                    .match(a);
+                return f && f.index > 0 ? null : (f && b !== !1 && (this.pos += f[0].length), f)
+            }
+            var d = function (a) {
+                    return c ? a.toLowerCase() : a
+                },
+                e = this.string.substr(this.pos, a.length);
+            return d(e) == d(a) ? (b !== !1 && (this.pos += a.length), !0) : void 0
+        },
+        current: function () {
+            return this.string.slice(this.start, this.pos)
+        },
+        hideFirstChars: function (a, b) {
+            this.lineStart += a;
+            try {
+                return b()
+            } finally {
+                this.lineStart -= a
+            }
+        }
+    };
+    var Td = 0,
+        Ud = v.TextMarker = function (a, b) {
+            this.lines = [], this.type = b, this.doc = a, this.id = ++Td
+        };
+    Sf(Ud), Ud.prototype.clear = function () {
+        if (!this.explicitlyCleared) {
+            var a = this.doc.cm,
+                b = a && !a.curOp;
+            if (b && Vb(a), Rf(this, "clear")) {
+                var c = this.find();
+                c && Nf(this, "clear", c.from, c.to)
+            }
+            for (var d = null, e = null, f = 0; f < this.lines.length; ++f) {
+                var g = this.lines[f],
+                    h = ae(g.markedSpans, this);
+                a && !this.collapsed ? jc(a, kf(g), "text") : a && (null != h.to && (e = kf(g)), null != h.from && (d = kf(g))), g.markedSpans = be(g.markedSpans, h), null == h.from && this.collapsed && !we(this.doc, g) && a && jf(g, Rb(a.display))
+            }
+            if (a && this.collapsed && !a.options.lineWrapping)
+                for (var f = 0; f < this.lines.length; ++f) {
+                    var i = se(this.lines[f]),
+                        j = G(i);
+                    j > a.display.maxLineLength && (a.display.maxLine = i, a.display.maxLineLength = j, a.display.maxLineChanged = !0)
+                }
+            null != d && a && this.collapsed && ic(a, d, e + 1), this.lines.length = 0, this.explicitlyCleared = !0, this.atomic && this.doc.cantEdit && (this.doc.cantEdit = !1, a && ab(a.doc)), a && Nf(a, "markerCleared", a, this), b && Xb(a), this.parent && this.parent.clear()
+        }
+    }, Ud.prototype.find = function (a, b) {
+        null == a && "bookmark" == this.type && (a = 1);
+        for (var c, d, e = 0; e < this.lines.length; ++e) {
+            var f = this.lines[e],
+                g = ae(f.markedSpans, this);
+            if (null != g.from && (c = oa(b ? f : kf(f), g.from), -1 == a)) return c;
+            if (null != g.to && (d = oa(b ? f : kf(f), g.to), 1 == a)) return d
+        }
+        return c && {
+            from: c,
+            to: d
+        }
+    }, Ud.prototype.changed = function () {
+        var a = this.find(-1, !0),
+            b = this,
+            c = this.doc.cm;
+        a && c && cc(c, function () {
+            var d = a.line,
+                e = kf(a.line),
+                f = wb(c, e);
+            if (f && (Db(f), c.curOp.selectionChanged = c.curOp.forceUpdate = !0), c.curOp.updateMaxLine = !0, !we(b.doc, d) && null != b.height) {
+                var g = b.height;
+                b.height = null;
+                var h = Ae(b) - g;
+                h && jf(d, d.height + h)
+            }
+        })
+    }, Ud.prototype.attachLine = function (a) {
+        if (!this.lines.length && this.doc.cm) {
+            var b = this.doc.cm.curOp;
+            b.maybeHiddenMarkers && -1 != dg(b.maybeHiddenMarkers, this) || (b.maybeUnhiddenMarkers || (b.maybeUnhiddenMarkers = []))
+                .push(this)
+        }
+        this.lines.push(a)
+    }, Ud.prototype.detachLine = function (a) {
+        if (this.lines.splice(dg(this.lines, a), 1), !this.lines.length && this.doc.cm) {
+            var b = this.doc.cm.curOp;
+            (b.maybeHiddenMarkers || (b.maybeHiddenMarkers = []))
+            .push(this)
+        }
+    };
+    var Td = 0,
+        Wd = v.SharedTextMarker = function (a, b) {
+            this.markers = a, this.primary = b;
+            for (var c = 0; c < a.length; ++c) a[c].parent = this
+        };
+    Sf(Wd), Wd.prototype.clear = function () {
+        if (!this.explicitlyCleared) {
+            this.explicitlyCleared = !0;
+            for (var a = 0; a < this.markers.length; ++a) this.markers[a].clear();
+            Nf(this, "clear")
+        }
+    }, Wd.prototype.find = function (a, b) {
+        return this.primary.find(a, b)
+    };
+    var ye = v.LineWidget = function (a, b, c) {
+        if (c)
+            for (var d in c) c.hasOwnProperty(d) && (this[d] = c[d]);
+        this.doc = a, this.node = b
+    };
+    Sf(ye), ye.prototype.clear = function () {
+        var a = this.doc.cm,
+            b = this.line.widgets,
+            c = this.line,
+            d = kf(c);
+        if (null != d && b) {
+            for (var e = 0; e < b.length; ++e) b[e] == this && b.splice(e--, 1);
+            b.length || (c.widgets = null);
+            var f = Ae(this);
+            jf(c, Math.max(0, c.height - f)), a && cc(a, function () {
+                ze(a, c, -f), jc(a, d, "widget")
+            })
+        }
+    }, ye.prototype.changed = function () {
+        var a = this.height,
+            b = this.doc.cm,
+            c = this.line;
+        this.height = null;
+        var d = Ae(this) - a;
+        d && (jf(c, c.height + d), b && cc(b, function () {
+            b.curOp.forceUpdate = !0, ze(b, c, d)
+        }))
+    };
+    var Ce = v.Line = function (a, b, c) {
+        this.text = a, ke(this, b), this.height = c ? c(this) : 1
+    };
+    Sf(Ce), Ce.prototype.lineNo = function () {
+        return kf(this)
+    };
+    var Ne = {},
+        Oe = {};
+    Ze.prototype = {
+        chunkSize: function () {
+            return this.lines.length
+        },
+        removeInner: function (a, b) {
+            for (var c = a, d = a + b; d > c; ++c) {
+                var e = this.lines[c];
+                this.height -= e.height, Ee(e), Nf(e, "delete")
+            }
+            this.lines.splice(a, b)
+        },
+        collapse: function (a) {
+            a.push.apply(a, this.lines)
+        },
+        insertInner: function (a, b, c) {
+            this.height += c, this.lines = this.lines.slice(0, a)
+                .concat(b)
+                .concat(this.lines.slice(a));
+            for (var d = 0; d < b.length; ++d) b[d].parent = this
+        },
+        iterN: function (a, b, c) {
+            for (var d = a + b; d > a; ++a)
+                if (c(this.lines[a])) return !0
+        }
+    }, $e.prototype = {
+        chunkSize: function () {
+            return this.size
+        },
+        removeInner: function (a, b) {
+            this.size -= b;
+            for (var c = 0; c < this.children.length; ++c) {
+                var d = this.children[c],
+                    e = d.chunkSize();
+                if (e > a) {
+                    var f = Math.min(b, e - a),
+                        g = d.height;
+                    if (d.removeInner(a, f), this.height -= g - d.height, e == f && (this.children.splice(c--, 1), d.parent = null), 0 == (b -= f)) break;
+                    a = 0
+                } else a -= e
+            }
+            if (this.size - b < 25 && (this.children.length > 1 || !(this.children[0] instanceof Ze))) {
+                var h = [];
+                this.collapse(h), this.children = [new Ze(h)], this.children[0].parent = this
+            }
+        },
+        collapse: function (a) {
+            for (var b = 0; b < this.children.length; ++b) this.children[b].collapse(a)
+        },
+        insertInner: function (a, b, c) {
+            this.size += b.length, this.height += c;
+            for (var d = 0; d < this.children.length; ++d) {
+                var e = this.children[d],
+                    f = e.chunkSize();
+                if (f >= a) {
+                    if (e.insertInner(a, b, c), e.lines && e.lines.length > 50) {
+                        for (; e.lines.length > 50;) {
+                            var g = e.lines.splice(e.lines.length - 25, 25),
+                                h = new Ze(g);
+                            e.height -= h.height, this.children.splice(d + 1, 0, h), h.parent = this
+                        }
+                        this.maybeSpill()
+                    }
+                    break
+                }
+                a -= f
+            }
+        },
+        maybeSpill: function () {
+            if (!(this.children.length <= 10)) {
+                var a = this;
+                do {
+                    var b = a.children.splice(a.children.length - 5, 5),
+                        c = new $e(b);
+                    if (a.parent) {
+                        a.size -= c.size, a.height -= c.height;
+                        var e = dg(a.parent.children, a);
+                        a.parent.children.splice(e + 1, 0, c)
+                    } else {
+                        var d = new $e(a.children);
+                        d.parent = a, a.children = [d, c], a = d
+                    }
+                    c.parent = a.parent
+                } while (a.children.length > 10);
+                a.parent.maybeSpill()
+            }
+        },
+        iterN: function (a, b, c) {
+            for (var d = 0; d < this.children.length; ++d) {
+                var e = this.children[d],
+                    f = e.chunkSize();
+                if (f > a) {
+                    var g = Math.min(b, f - a);
+                    if (e.iterN(a, g, c)) return !0;
+                    if (0 == (b -= g)) break;
+                    a = 0
+                } else a -= f
+            }
+        }
+    };
+    var _e = 0,
+        af = v.Doc = function (a, b, c, d) {
+            if (!(this instanceof af)) return new af(a, b, c, d);
+            null == c && (c = 0), $e.call(this, [new Ze([new Ce("", null)])]), this.first = c, this.scrollTop = this.scrollLeft = 0, this.cantEdit = !1, this.cleanGeneration = 1, this.frontier = c;
+            var e = oa(c, 0);
+            this.sel = Ma(e), this.history = new of(null), this.id = ++_e, this.modeOption = b, this.lineSep = d, "string" == typeof a && (a = this.splitLines(a)), Ye(this, {
+                from: e,
+                to: e,
+                text: a
+            }), Za(this, Ma(e), Vf)
+        };
+    af.prototype = gg($e.prototype, {
+        constructor: af,
+        iter: function (a, b, c) {
+            c ? this.iterN(a - this.first, b - a, c) : this.iterN(this.first, this.first + this.size, a)
+        },
+        insert: function (a, b) {
+            for (var c = 0, d = 0; d < b.length; ++d) c += b[d].height;
+            this.insertInner(a - this.first, b, c)
+        },
+        remove: function (a, b) {
+            this.removeInner(a - this.first, b)
+        },
+        getValue: function (a) {
+            var b = hf(this, this.first, this.first + this.size);
+            return a === !1 ? b : b.join(a || this.lineSeparator())
+        },
+        setValue: fc(function (a) {
+            var b = oa(this.first, 0),
+                c = this.first + this.size - 1;
+            hd(this, {
+                from: b,
+                to: oa(c, ff(this, c)
+                    .text.length),
+                text: this.splitLines(a),
+                origin: "setValue",
+                full: !0
+            }, !0), Za(this, Ma(b))
+        }),
+        replaceRange: function (a, b, c, d) {
+            b = Oa(this, b), c = c ? Oa(this, c) : b, nd(this, a, b, c, d)
+        },
+        getRange: function (a, b, c) {
+            var d = gf(this, Oa(this, a), Oa(this, b));
+            return c === !1 ? d : d.join(c || this.lineSeparator())
+        },
+        getLine: function (a) {
+            var b = this.getLineHandle(a);
+            return b && b.text
+        },
+        getLineHandle: function (a) {
+            return Qa(this, a) ? ff(this, a) : void 0
+        },
+        getLineNumber: function (a) {
+            return kf(a)
+        },
+        getLineHandleVisualStart: function (a) {
+            return "number" == typeof a && (a = ff(this, a)), se(a)
+        },
+        lineCount: function () {
+            return this.size
+        },
+        firstLine: function () {
+            return this.first
+        },
+        lastLine: function () {
+            return this.first + this.size - 1
+        },
+        clipPos: function (a) {
+            return Oa(this, a)
+        },
+        getCursor: function (a) {
+            var c, b = this.sel.primary();
+            return c = null == a || "head" == a ? b.head : "anchor" == a ? b.anchor : "end" == a || "to" == a || a === !1 ? b.to() : b.from()
+        },
+        listSelections: function () {
+            return this.sel.ranges
+        },
+        somethingSelected: function () {
+            return this.sel.somethingSelected()
+        },
+        setCursor: fc(function (a, b, c) {
+            Wa(this, Oa(this, "number" == typeof a ? oa(a, b || 0) : a), null, c)
+        }),
+        setSelection: fc(function (a, b, c) {
+            Wa(this, Oa(this, a), Oa(this, b || a), c)
+        }),
+        extendSelection: fc(function (a, b, c) {
+            Ta(this, Oa(this, a), b && Oa(this, b), c)
+        }),
+        extendSelections: fc(function (a, b) {
+            Ua(this, Ra(this, a, b))
+        }),
+        extendSelectionsBy: fc(function (a, b) {
+            Ua(this, eg(this.sel.ranges, a), b)
+        }),
+        setSelections: fc(function (a, b, c) {
+            if (a.length) {
+                for (var d = 0, e = []; d < a.length; d++) e[d] = new Ka(Oa(this, a[d].anchor), Oa(this, a[d].head));
+                null == b && (b = Math.min(a.length - 1, this.sel.primIndex)), Za(this, La(e, b), c)
+            }
+        }),
+        addSelection: fc(function (a, b, c) {
+            var d = this.sel.ranges.slice(0);
+            d.push(new Ka(Oa(this, a), Oa(this, b || a))), Za(this, La(d, d.length - 1), c)
+        }),
+        getSelection: function (a) {
+            for (var c, b = this.sel.ranges, d = 0; d < b.length; d++) {
+                var e = gf(this, b[d].from(), b[d].to());
+                c = c ? c.concat(e) : e
+            }
+            return a === !1 ? c : c.join(a || this.lineSeparator())
+        },
+        getSelections: function (a) {
+            for (var b = [], c = this.sel.ranges, d = 0; d < c.length; d++) {
+                var e = gf(this, c[d].from(), c[d].to());
+                a !== !1 && (e = e.join(a || this.lineSeparator())), b[d] = e
+            }
+            return b
+        },
+        replaceSelection: function (a, b, c) {
+            for (var d = [], e = 0; e < this.sel.ranges.length; e++) d[e] = a;
+            this.replaceSelections(d, b, c || "+input")
+        },
+        replaceSelections: fc(function (a, b, c) {
+            for (var d = [], e = this.sel, f = 0; f < e.ranges.length; f++) {
+                var g = e.ranges[f];
+                d[f] = {
+                    from: g.from(),
+                    to: g.to(),
+                    text: this.splitLines(a[f]),
+                    origin: c
+                }
+            }
+            for (var h = b && "end" != b && fd(this, d, b), f = d.length - 1; f >= 0; f--) hd(this, d[f]);
+            h ? Ya(this, h) : this.cm && td(this.cm)
+        }),
+        undo: fc(function () {
+            jd(this, "undo")
+        }),
+        redo: fc(function () {
+            jd(this, "redo")
+        }),
+        undoSelection: fc(function () {
+            jd(this, "undo", !0)
+        }),
+        redoSelection: fc(function () {
+            jd(this, "redo", !0)
+        }),
+        setExtending: function (a) {
+            this.extend = a
+        },
+        getExtending: function () {
+            return this.extend
+        },
+        historySize: function () {
+            for (var a = this.history, b = 0, c = 0, d = 0; d < a.done.length; d++) a.done[d].ranges || ++b;
+            for (var d = 0; d < a.undone.length; d++) a.undone[d].ranges || ++c;
+            return {
+                undo: b,
+                redo: c
+            }
+        },
+        clearHistory: function () {
+            this.history = new of(this.history.maxGeneration)
+        },
+        markClean: function () {
+            this.cleanGeneration = this.changeGeneration(!0)
+        },
+        changeGeneration: function (a) {
+            return a && (this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null), this.history.generation
+        },
+        isClean: function (a) {
+            return this.history.generation == (a || this.cleanGeneration)
+        },
+        getHistory: function () {
+            return {
+                done: zf(this.history.done),
+                undone: zf(this.history.undone)
+            }
+        },
+        setHistory: function (a) {
+            var b = this.history = new of(this.history.maxGeneration);
+            b.done = zf(a.done.slice(0), null, !0), b.undone = zf(a.undone.slice(0), null, !0)
+        },
+        addLineClass: fc(function (a, b, c) {
+            return wd(this, a, "gutter" == b ? "gutter" : "class", function (a) {
+                var d = "text" == b ? "textClass" : "background" == b ? "bgClass" : "gutter" == b ? "gutterClass" : "wrapClass";
+                if (a[d]) {
+                    if (vg(c)
+                        .test(a[d])) return !1;
+                    a[d] += " " + c
+                } else a[d] = c;
+                return !0
+            })
+        }),
+        removeLineClass: fc(function (a, b, c) {
+            return wd(this, a, "gutter" == b ? "gutter" : "class", function (a) {
+                var d = "text" == b ? "textClass" : "background" == b ? "bgClass" : "gutter" == b ? "gutterClass" : "wrapClass",
+                    e = a[d];
+                if (!e) return !1;
+                if (null == c) a[d] = null;
+                else {
+                    var f = e.match(vg(c));
+                    if (!f) return !1;
+                    var g = f.index + f[0].length;
+                    a[d] = e.slice(0, f.index) + (f.index && g != e.length ? " " : "") + e.slice(g) || null
+                }
+                return !0
+            })
+        }),
+        addLineWidget: fc(function (a, b, c) {
+            return Be(this, a, b, c)
+        }),
+        removeLineWidget: function (a) {
+            a.clear()
+        },
+        markText: function (a, b, c) {
+            return Vd(this, Oa(this, a), Oa(this, b), c, "range")
+        },
+        setBookmark: function (a, b) {
+            var c = {
+                replacedWith: b && (null == b.nodeType ? b.widget : b),
+                insertLeft: b && b.insertLeft,
+                clearWhenEmpty: !1,
+                shared: b && b.shared,
+                handleMouseEvents: b && b.handleMouseEvents
+            };
+            return a = Oa(this, a), Vd(this, a, a, c, "bookmark")
+        },
+        findMarksAt: function (a) {
+            a = Oa(this, a);
+            var b = [],
+                c = ff(this, a.line)
+                .markedSpans;
+            if (c)
+                for (var d = 0; d < c.length; ++d) {
+                    var e = c[d];
+                    (null == e.from || e.from <= a.ch) && (null == e.to || e.to >= a.ch) && b.push(e.marker.parent || e.marker)
+                }
+            return b
+        },
+        findMarks: function (a, b, c) {
+            a = Oa(this, a), b = Oa(this, b);
+            var d = [],
+                e = a.line;
+            return this.iter(a.line, b.line + 1, function (f) {
+                var g = f.markedSpans;
+                if (g)
+                    for (var h = 0; h < g.length; h++) {
+                        var i = g[h];
+                        e == a.line && a.ch > i.to || null == i.from && e != a.line || e == b.line && i.from > b.ch || c && !c(i.marker) || d.push(i.marker.parent || i.marker)
+                    }++e
+            }), d
+        },
+        getAllMarks: function () {
+            var a = [];
+            return this.iter(function (b) {
+                var c = b.markedSpans;
+                if (c)
+                    for (var d = 0; d < c.length; ++d) null != c[d].from && a.push(c[d].marker)
+            }), a
+        },
+        posFromIndex: function (a) {
+            var b, c = this.first;
+            return this.iter(function (d) {
+                var e = d.text.length + 1;
+                return e > a ? (b = a, !0) : (a -= e, void++c)
+            }), Oa(this, oa(c, b))
+        },
+        indexFromPos: function (a) {
+            a = Oa(this, a);
+            var b = a.ch;
+            return a.line < this.first || a.ch < 0 ? 0 : (this.iter(this.first, a.line, function (a) {
+                b += a.text.length + 1
+            }), b)
+        },
+        copy: function (a) {
+            var b = new af(hf(this, this.first, this.first + this.size), this.modeOption, this.first, this.lineSep);
+            return b.scrollTop = this.scrollTop, b.scrollLeft = this.scrollLeft, b.sel = this.sel, b.extend = !1, a && (b.history.undoDepth = this.history.undoDepth, b.setHistory(this.getHistory())), b
+        },
+        linkedDoc: function (a) {
+            a || (a = {});
+            var b = this.first,
+                c = this.first + this.size;
+            null != a.from && a.from > b && (b = a.from), null != a.to && a.to < c && (c = a.to);
+            var d = new af(hf(this, b, c), a.mode || this.modeOption, b, this.lineSep);
+            return a.sharedHist && (d.history = this.history), (this.linked || (this.linked = []))
+                .push({
+                    doc: d,
+                    sharedHist: a.sharedHist
+                }), d.linked = [{
+                    doc: this,
+                    isParent: !0,
+                    sharedHist: a.sharedHist
+                }], Zd(d, Yd(this)), d
+        },
+        unlinkDoc: function (a) {
+            if (a instanceof v && (a = a.doc), this.linked)
+                for (var b = 0; b < this.linked.length; ++b) {
+                    var c = this.linked[b];
+                    if (c.doc == a) {
+                        this.linked.splice(b, 1), a.unlinkDoc(this), $d(Yd(this));
+                        break
+                    }
+                }
+            if (a.history == this.history) {
+                var d = [a.id];
+                df(a, function (a) {
+                    d.push(a.id)
+                }, !0), a.history = new of(null), a.history.done = zf(this.history.done, d), a.history.undone = zf(this.history.undone, d)
+            }
+        },
+        iterLinkedDocs: function (a) {
+            df(this, a)
+        },
+        getMode: function () {
+            return this.mode
+        },
+        getEditor: function () {
+            return this.cm
+        },
+        splitLines: function (a) {
+            return this.lineSep ? a.split(this.lineSep) : Ig(a)
+        },
+        lineSeparator: function () {
+            return this.lineSep || "\n"
+        }
+    }), af.prototype.eachLine = af.prototype.iter;
+    var bf = "iter insert remove copy getEditor constructor".split(" ");
+    for (var cf in af.prototype) af.prototype.hasOwnProperty(cf) && dg(bf, cf) < 0 && (v.prototype[cf] = function (a) {
+        return function () {
+            return a.apply(this.doc, arguments)
+        }
+    }(af.prototype[cf]));
+    Sf(af);
+    var Df = v.e_preventDefault = function (a) {
+            a.preventDefault ? a.preventDefault() : a.returnValue = !1
+        },
+        Ef = v.e_stopPropagation = function (a) {
+            a.stopPropagation ? a.stopPropagation() : a.cancelBubble = !0
+        },
+        Gf = v.e_stop = function (a) {
+            Df(a), Ef(a)
+        },
+        Jf = v.on = function (a, b, c) {
+            if (a.addEventListener) a.addEventListener(b, c, !1);
+            else if (a.attachEvent) a.attachEvent("on" + b, c);
+            else {
+                var d = a._handlers || (a._handlers = {}),
+                    e = d[b] || (d[b] = []);
+                e.push(c)
+            }
+        },
+        Kf = v.off = function (a, b, c) {
+            if (a.removeEventListener) a.removeEventListener(b, c, !1);
+            else if (a.detachEvent) a.detachEvent("on" + b, c);
+            else {
+                var d = a._handlers && a._handlers[b];
+                if (!d) return;
+                for (var e = 0; e < d.length; ++e)
+                    if (d[e] == c) {
+                        d.splice(e, 1);
+                        break
+                    }
+            }
+        },
+        Lf = v.signal = function (a, b) {
+            var c = a._handlers && a._handlers[b];
+            if (c)
+                for (var d = Array.prototype.slice.call(arguments, 2), e = 0; e < c.length; ++e) c[e].apply(null, d)
+        },
+        Mf = null,
+        Tf = 30,
+        Uf = v.Pass = {
+            toString: function () {
+                return "CodeMirror.Pass"
+            }
+        },
+        Vf = {
+            scroll: !1
+        },
+        Wf = {
+            origin: "*mouse"
+        },
+        Xf = {
+            origin: "+move"
+        };
+    Yf.prototype.set = function (a, b) {
+        clearTimeout(this.id), this.id = setTimeout(b, a)
+    };
+    var Zf = v.countColumn = function (a, b, c, d, e) {
+            null == b && (b = a.search(/[^\s\u00a0]/), -1 == b && (b = a.length));
+            for (var f = d || 0, g = e || 0;;) {
+                var h = a.indexOf("	", f);
+                if (0 > h || h >= b) return g + (b - f);
+                g += h - f, g += c - g % c, f = h + 1
+            }
+        },
+        $f = v.findColumn = function (a, b, c) {
+            for (var d = 0, e = 0;;) {
+                var f = a.indexOf("	", d); - 1 == f && (f = a.length);
+                var g = f - d;
+                if (f == a.length || e + g >= b) return d + Math.min(g, b - e);
+                if (e += f - d, e += c - e % c, d = f + 1, e >= b) return d
+            }
+        },
+        _f = [""],
+        cg = function (a) {
+            a.select()
+        };
+    m ? cg = function (a) {
+        a.selectionStart = 0, a.selectionEnd = a.value.length
+    } : d && (cg = function (a) {
+        try {
+            a.select()
+        } catch (b) {}
+    });
+    var qg, jg = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/,
+        kg = v.isWordChar = function (a) {
+            return /\w/.test(a) || a > "\x80" && (a.toUpperCase() != a.toLowerCase() || jg.test(a))
+        },
+        ng = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
+    qg = document.createRange ? function (a, b, c, d) {
+        var e = document.createRange();
+        return e.setEnd(d || a, c), e.setStart(a, b), e
+    } : function (a, b, c) {
+        var d = document.body.createTextRange();
+        try {
+            d.moveToElementText(a.parentNode)
+        } catch (e) {
+            return d
+        }
+        return d.collapse(!0), d.moveEnd("character", c), d.moveStart("character", b), d
+    };
+    var tg = v.contains = function (a, b) {
+        if (3 == b.nodeType && (b = b.parentNode), a.contains) return a.contains(b);
+        do
+            if (11 == b.nodeType && (b = b.host), b == a) return !0;
+        while (b = b.parentNode)
+    };
+    d && 11 > e && (ug = function () {
+        try {
+            return document.activeElement
+        } catch (a) {
+            return document.body
+        }
+    });
+    var Eg, Gg, wg = v.rmClass = function (a, b) {
+            var c = a.className,
+                d = vg(b)
+                .exec(c);
+            if (d) {
+                var e = c.slice(d.index + d[0].length);
+                a.className = c.slice(0, d.index) + (e ? d[1] + e : "")
+            }
+        },
+        xg = v.addClass = function (a, b) {
+            var c = a.className;
+            vg(b)
+                .test(c) || (a.className += (c ? " " : "") + b)
+        },
+        Ag = !1,
+        Dg = function () {
+            if (d && 9 > e) return !1;
+            var a = pg("div");
+            return "draggable" in a || "dragDrop" in a
+        }(),
+        Ig = v.splitLines = 3 != "\n\nb".split(/\n/)
+        .length ? function (a) {
+            for (var b = 0, c = [], d = a.length; d >= b;) {
+                var e = a.indexOf("\n", b); - 1 == e && (e = a.length);
+                var f = a.slice(b, "\r" == a.charAt(e - 1) ? e - 1 : e),
+                    g = f.indexOf("\r"); - 1 != g ? (c.push(f.slice(0, g)), b += g + 1) : (c.push(f), b = e + 1)
+            }
+            return c
+        } : function (a) {
+            return a.split(/\r\n?|\n/)
+        },
+        Jg = window.getSelection ? function (a) {
+            try {
+                return a.selectionStart != a.selectionEnd
+            } catch (b) {
+                return !1
+            }
+        } : function (a) {
+            try {
+                var b = a.ownerDocument.selection.createRange()
+            } catch (c) {}
+            return b && b.parentElement() == a ? 0 != b.compareEndPoints("StartToEnd", b) : !1
+        },
+        Kg = function () {
+            var a = pg("div");
+            return "oncopy" in a ? !0 : (a.setAttribute("oncopy", "return;"), "function" == typeof a.oncopy)
+        }(),
+        Lg = null,
+        Ng = {
+            3: "Enter",
+            8: "Backspace",
+            9: "Tab",
+            13: "Enter",
+            16: "Shift",
+            17: "Ctrl",
+            18: "Alt",
+            19: "Pause",
+            20: "CapsLock",
+            27: "Esc",
+            32: "Space",
+            33: "PageUp",
+            34: "PageDown",
+            35: "End",
+            36: "Home",
+            37: "Left",
+            38: "Up",
+            39: "Right",
+            40: "Down",
+            44: "PrintScrn",
+            45: "Insert",
+            46: "Delete",
+            59: ";",
+            61: "=",
+            91: "Mod",
+            92: "Mod",
+            93: "Mod",
+            107: "=",
+            109: "-",
+            127: "Delete",
+            173: "-",
+            186: ";",
+            187: "=",
+            188: ",",
+            189: "-",
+            190: ".",
+            191: "/",
+            192: "`",
+            219: "[",
+            220: "\\",
+            221: "]",
+            222: "'",
+            63232: "Up",
+            63233: "Down",
+            63234: "Left",
+            63235: "Right",
+            63272: "Delete",
+            63273: "Home",
+            63275: "End",
+            63276: "PageUp",
+            63277: "PageDown",
+            63302: "Insert"
+        };
+    v.keyNames = Ng,
+        function () {
+            for (var a = 0; 10 > a; a++) Ng[a + 48] = Ng[a + 96] = String(a);
+            for (var a = 65; 90 >= a; a++) Ng[a] = String.fromCharCode(a);
+            for (var a = 1; 12 >= a; a++) Ng[a + 111] = Ng[a + 63235] = "F" + a
+        }();
+    var Xg, ah = function () {
+        function c(c) {
+            return 247 >= c ? a.charAt(c) : c >= 1424 && 1524 >= c ? "R" : c >= 1536 && 1773 >= c ? b.charAt(c - 1536) : c >= 1774 && 2220 >= c ? "r" : c >= 8192 && 8203 >= c ? "w" : 8204 == c ? "b" : "L"
+        }
+
+        function j(a, b, c) {
+            this.level = a, this.from = b, this.to = c
+        }
+        var a = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",
+            b = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm",
+            d = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,
+            e = /[stwN]/,
+            f = /[LRr]/,
+            g = /[Lb1n]/,
+            h = /[1n]/,
+            i = "L";
+        return function (a) {
+            if (!d.test(a)) return !1;
+            for (var m, b = a.length, k = [], l = 0; b > l; ++l) k.push(m = c(a.charCodeAt(l)));
+            for (var l = 0, n = i; b > l; ++l) {
+                var m = k[l];
+                "m" == m ? k[l] = n : n = m
+            }
+            for (var l = 0, o = i; b > l; ++l) {
+                var m = k[l];
+                "1" == m && "r" == o ? k[l] = "n" : f.test(m) && (o = m, "r" == m && (k[l] = "R"))
+            }
+            for (var l = 1, n = k[0]; b - 1 > l; ++l) {
+                var m = k[l];
+                "+" == m && "1" == n && "1" == k[l + 1] ? k[l] = "1" : "," != m || n != k[l + 1] || "1" != n && "n" != n || (k[l] = n), n = m
+            }
+            for (var l = 0; b > l; ++l) {
+                var m = k[l];
+                if ("," == m) k[l] = "N";
+                else if ("%" == m) {
+                    for (var p = l + 1; b > p && "%" == k[p]; ++p);
+                    for (var q = l && "!" == k[l - 1] || b > p && "1" == k[p] ? "1" : "N", r = l; p > r; ++r) k[r] = q;
+                    l = p - 1
+                }
+            }
+            for (var l = 0, o = i; b > l; ++l) {
+                var m = k[l];
+                "L" == o && "1" == m ? k[l] = "L" : f.test(m) && (o = m)
+            }
+            for (var l = 0; b > l; ++l)
+                if (e.test(k[l])) {
+                    for (var p = l + 1; b > p && e.test(k[p]); ++p);
+                    for (var s = "L" == (l ? k[l - 1] : i), t = "L" == (b > p ? k[p] : i), q = s || t ? "L" : "R", r = l; p > r; ++r) k[r] = q;
+                    l = p - 1
+                }
+            for (var v, u = [], l = 0; b > l;)
+                if (g.test(k[l])) {
+                    var w = l;
+                    for (++l; b > l && g.test(k[l]); ++l);
+                    u.push(new j(0, w, l))
+                } else {
+                    var x = l,
+                        y = u.length;
+                    for (++l; b > l && "L" != k[l]; ++l);
+                    for (var r = x; l > r;)
+                        if (h.test(k[r])) {
+                            r > x && u.splice(y, 0, new j(1, x, r));
+                            var z = r;
+                            for (++r; l > r && h.test(k[r]); ++r);
+                            u.splice(y, 0, new j(2, z, r)), x = r
+                        } else ++r;
+                    l > x && u.splice(y, 0, new j(1, x, l))
+                }
+            return 1 == u[0].level && (v = a.match(/^\s+/)) && (u[0].from = v[0].length, u.unshift(new j(0, 0, v[0].length))), 1 == bg(u)
+                .level && (v = a.match(/\s+$/)) && (bg(u)
+                    .to -= v[0].length, u.push(new j(0, b - v[0].length, b))), 2 == u[0].level && u.unshift(new j(1, u[0].to, u[0].to)), u[0].level != bg(u)
+                .level && u.push(new j(u[0].level, b, b)), u
+        }
+    }();
+    return v.version = "5.6.1", v
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+
+    function b(a) {
+        for (var b = {}, c = 0; c < a.length; ++c) b[a[c]] = !0;
+        return b
+    }
+
+    function x(a, b) {
+        for (var d, c = !1; null != (d = a.next());) {
+            if (c && "/" == d) {
+                b.tokenize = null;
+                break
+            }
+            c = "*" == d
+        }
+        return ["comment", "comment"]
+    }
+    a.defineMode("css", function (b, c) {
+        function u(a, b) {
+            return s = b, a
+        }
+
+        function v(a, b) {
+            var c = a.next();
+            if (f[c]) {
+                var d = f[c](a, b);
+                if (d !== !1) return d
+            }
+            return "@" == c ? (a.eatWhile(/[\w\\\-]/), u("def", a.current())) : "=" == c || ("~" == c || "|" == c) && a.eat("=") ? u(null, "compare") : '"' == c || "'" == c ? (b.tokenize = w(c), b.tokenize(a, b)) : "#" == c ? (a.eatWhile(/[\w\\\-]/), u("atom", "hash")) : "!" == c ? (a.match(/^\s*\w*/), u("keyword", "important")) : /\d/.test(c) || "." == c && a.eat(/\d/) ? (a.eatWhile(/[\w.%]/), u("number", "unit")) : "-" !== c ? /[,+>*\/]/.test(c) ? u(null, "select-op") : "." == c && a.match(/^-?[_a-z][_a-z0-9-]*/i) ? u("qualifier", "qualifier") : /[:;{}\[\]\(\)]/.test(c) ? u(null, c) : "u" == c && a.match(/rl(-prefix)?\(/) || "d" == c && a.match("omain(") || "r" == c && a.match("egexp(") ? (a.backUp(1), b.tokenize = x, u("property", "word")) : /[\w\\\-]/.test(c) ? (a.eatWhile(/[\w\\\-]/), u("property", "word")) : u(null, null) : /[\d.]/.test(a.peek()) ? (a.eatWhile(/[\w.%]/), u("number", "unit")) : a.match(/^-[\w\\\-]+/) ? (a.eatWhile(/[\w\\\-]/), a.match(/^\s*:/, !1) ? u("variable-2", "variable-definition") : u("variable-2", "variable")) : a.match(/^\w+-/) ? u("meta", "meta") : void 0
+        }
+
+        function w(a) {
+            return function (b, c) {
+                for (var e, d = !1; null != (e = b.next());) {
+                    if (e == a && !d) {
+                        ")" == a && b.backUp(1);
+                        break
+                    }
+                    d = !d && "\\" == e
+                }
+                return (e == a || !d && ")" != a) && (c.tokenize = null), u("string", "string")
+            }
+        }
+
+        function x(a, b) {
+            return a.next(), a.match(/\s*[\"\')]/, !1) ? b.tokenize = null : b.tokenize = w(")"), u(null, "(")
+        }
+
+        function y(a, b, c) {
+            this.type = a, this.indent = b, this.prev = c
+        }
+
+        function z(a, b, c, d) {
+            return a.context = new y(c, b.indentation() + (d === !1 ? 0 : e), a.context), c
+        }
+
+        function A(a) {
+            return a.context.prev && (a.context = a.context.prev), a.context.type
+        }
+
+        function B(a, b, c) {
+            return E[c.context.type](a, b, c)
+        }
+
+        function C(a, b, c, d) {
+            for (var e = d || 1; e > 0; e--) c.context = c.context.prev;
+            return B(a, b, c)
+        }
+
+        function D(a) {
+            var b = a.current()
+                .toLowerCase();
+            t = p.hasOwnProperty(b) ? "atom" : o.hasOwnProperty(b) ? "keyword" : "variable"
+        }
+        var d = c;
+        c.propertyKeywords || (c = a.resolveMode("text/css")), c.inline = d.inline;
+        var s, t, e = b.indentUnit,
+            f = c.tokenHooks,
+            g = c.documentTypes || {},
+            h = c.mediaTypes || {},
+            i = c.mediaFeatures || {},
+            j = c.mediaValueKeywords || {},
+            k = c.propertyKeywords || {},
+            l = c.nonStandardPropertyKeywords || {},
+            m = c.fontProperties || {},
+            n = c.counterDescriptors || {},
+            o = c.colorKeywords || {},
+            p = c.valueKeywords || {},
+            q = c.allowNested,
+            r = c.supportsAtComponent === !0,
+            E = {};
+        return E.top = function (a, b, c) {
+            if ("{" == a) return z(c, b, "block");
+            if ("}" == a && c.context.prev) return A(c);
+            if (r && /@component/.test(a)) return z(c, b, "atComponentBlock");
+            if (/^@(-moz-)?document$/.test(a)) return z(c, b, "documentTypes");
+            if (/^@(media|supports|(-moz-)?document|import)$/.test(a)) return z(c, b, "atBlock");
+            if (/^@(font-face|counter-style)/.test(a)) return c.stateArg = a, "restricted_atBlock_before";
+            if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(a)) return "keyframes";
+            if (a && "@" == a.charAt(0)) return z(c, b, "at");
+            if ("hash" == a) t = "builtin";
+            else if ("word" == a) t = "tag";
+            else {
+                if ("variable-definition" == a) return "maybeprop";
+                if ("interpolation" == a) return z(c, b, "interpolation");
+                if (":" == a) return "pseudo";
+                if (q && "(" == a) return z(c, b, "parens")
+            }
+            return c.context.type
+        }, E.block = function (a, b, c) {
+            if ("word" == a) {
+                var d = b.current()
+                    .toLowerCase();
+                return k.hasOwnProperty(d) ? (t = "property", "maybeprop") : l.hasOwnProperty(d) ? (t = "string-2", "maybeprop") : q ? (t = b.match(/^\s*:(?:\s|$)/, !1) ? "property" : "tag", "block") : (t += " error", "maybeprop")
+            }
+            return "meta" == a ? "block" : q || "hash" != a && "qualifier" != a ? E.top(a, b, c) : (t = "error", "block")
+        }, E.maybeprop = function (a, b, c) {
+            return ":" == a ? z(c, b, "prop") : B(a, b, c)
+        }, E.prop = function (a, b, c) {
+            if (";" == a) return A(c);
+            if ("{" == a && q) return z(c, b, "propBlock");
+            if ("}" == a || "{" == a) return C(a, b, c);
+            if ("(" == a) return z(c, b, "parens");
+            if ("hash" != a || /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(b.current())) {
+                if ("word" == a) D(b);
+                else if ("interpolation" == a) return z(c, b, "interpolation")
+            } else t += " error";
+            return "prop"
+        }, E.propBlock = function (a, b, c) {
+            return "}" == a ? A(c) : "word" == a ? (t = "property", "maybeprop") : c.context.type
+        }, E.parens = function (a, b, c) {
+            return "{" == a || "}" == a ? C(a, b, c) : ")" == a ? A(c) : "(" == a ? z(c, b, "parens") : "interpolation" == a ? z(c, b, "interpolation") : ("word" == a && D(b), "parens")
+        }, E.pseudo = function (a, b, c) {
+            return "word" == a ? (t = "variable-3", c.context.type) : B(a, b, c)
+        }, E.documentTypes = function (a, b, c) {
+            return "word" == a && g.hasOwnProperty(b.current()) ? (t = "tag", c.context.type) : E.atBlock(a, b, c)
+        }, E.atBlock = function (a, b, c) {
+            if ("(" == a) return z(c, b, "atBlock_parens");
+            if ("}" == a || ";" == a) return C(a, b, c);
+            if ("{" == a) return A(c) && z(c, b, q ? "block" : "top");
+            if ("word" == a) {
+                var d = b.current()
+                    .toLowerCase();
+                t = "only" == d || "not" == d || "and" == d || "or" == d ? "keyword" : h.hasOwnProperty(d) ? "attribute" : i.hasOwnProperty(d) ? "property" : j.hasOwnProperty(d) ? "keyword" : k.hasOwnProperty(d) ? "property" : l.hasOwnProperty(d) ? "string-2" : p.hasOwnProperty(d) ? "atom" : o.hasOwnProperty(d) ? "keyword" : "error"
+            }
+            return c.context.type
+        }, E.atComponentBlock = function (a, b, c) {
+            return "}" == a ? C(a, b, c) : "{" == a ? A(c) && z(c, b, q ? "block" : "top", !1) : ("word" == a && (t = "error"), c.context.type)
+        }, E.atBlock_parens = function (a, b, c) {
+            return ")" == a ? A(c) : "{" == a || "}" == a ? C(a, b, c, 2) : E.atBlock(a, b, c)
+        }, E.restricted_atBlock_before = function (a, b, c) {
+            return "{" == a ? z(c, b, "restricted_atBlock") : "word" == a && "@counter-style" == c.stateArg ? (t = "variable", "restricted_atBlock_before") : B(a, b, c)
+        }, E.restricted_atBlock = function (a, b, c) {
+            return "}" == a ? (c.stateArg = null, A(c)) : "word" == a ? (t = "@font-face" == c.stateArg && !m.hasOwnProperty(b.current()
+                .toLowerCase()) || "@counter-style" == c.stateArg && !n.hasOwnProperty(b.current()
+                .toLowerCase()) ? "error" : "property", "maybeprop") : "restricted_atBlock"
+        }, E.keyframes = function (a, b, c) {
+            return "word" == a ? (t = "variable", "keyframes") : "{" == a ? z(c, b, "top") : B(a, b, c)
+        }, E.at = function (a, b, c) {
+            return ";" == a ? A(c) : "{" == a || "}" == a ? C(a, b, c) : ("word" == a ? t = "tag" : "hash" == a && (t = "builtin"), "at")
+        }, E.interpolation = function (a, b, c) {
+            return "}" == a ? A(c) : "{" == a || ";" == a ? C(a, b, c) : ("word" == a ? t = "variable" : "variable" != a && "(" != a && ")" != a && (t = "error"), "interpolation")
+        }, {
+            startState: function (a) {
+                return {
+                    tokenize: null,
+                    state: c.inline ? "block" : "top",
+                    stateArg: null,
+                    context: new y(c.inline ? "block" : "top", a || 0, null)
+                }
+            },
+            token: function (a, b) {
+                if (!b.tokenize && a.eatSpace()) return null;
+                var c = (b.tokenize || v)(a, b);
+                return c && "object" == typeof c && (s = c[1], c = c[0]), t = c, b.state = E[b.state](s, a, b), t
+            },
+            indent: function (a, b) {
+                var c = a.context,
+                    d = b && b.charAt(0),
+                    f = c.indent;
+                return "prop" != c.type || "}" != d && ")" != d || (c = c.prev), c.prev && ("}" != d || "block" != c.type && "top" != c.type && "interpolation" != c.type && "restricted_atBlock" != c.type ? (")" == d && ("parens" == c.type || "atBlock_parens" == c.type) || "{" == d && ("at" == c.type || "atBlock" == c.type)) && (f = Math.max(0, c.indent - e), c = c.prev) : (c = c.prev, f = c.indent)), f
+            },
+            electricChars: "}",
+            blockCommentStart: "/*",
+            blockCommentEnd: "*/",
+            fold: "brace"
+        }
+    });
+    var c = ["domain", "regexp", "url", "url-prefix"],
+        d = b(c),
+        e = ["all", "aural", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "embossed"],
+        f = b(e),
+        g = ["width", "min-width", "max-width", "height", "min-height", "max-height", "device-width", "min-device-width", "max-device-width", "device-height", "min-device-height", "max-device-height", "aspect-ratio", "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio", "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color", "max-color", "color-index", "min-color-index", "max-color-index", "monochrome", "min-monochrome", "max-monochrome", "resolution", "min-resolution", "max-resolution", "scan", "grid", "orientation", "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio", "pointer", "any-pointer", "hover", "any-hover"],
+        h = b(g),
+        i = ["landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover", "interlace", "progressive"],
+        j = b(i),
+        k = ["align-content", "align-items", "align-self", "alignment-adjust", "alignment-baseline", "anchor-point", "animation", "animation-delay", "animation-direction", "animation-duration", "animation-fill-mode", "animation-iteration-count", "animation-name", "animation-play-state", "animation-timing-function", "appearance", "azimuth", "backface-visibility", "background", "background-attachment", "background-clip", "background-color", "background-image", "background-origin", "background-position", "background-repeat", "background-size", "baseline-shift", "binding", "bleed", "bookmark-label", "bookmark-level", "bookmark-state", "bookmark-target", "border", "border-bottom", "border-bottom-color", "border-bottom-left-radius", "border-bottom-right-radius", "border-bottom-style", "border-bottom-width", "border-collapse", "border-color", "border-image", "border-image-outset", "border-image-repeat", "border-image-slice", "border-image-source", "border-image-width", "border-left", "border-left-color", "border-left-style", "border-left-width", "border-radius", "border-right", "border-right-color", "border-right-style", "border-right-width", "border-spacing", "border-style", "border-top", "border-top-color", "border-top-left-radius", "border-top-right-radius", "border-top-style", "border-top-width", "border-width", "bottom", "box-decoration-break", "box-shadow", "box-sizing", "break-after", "break-before", "break-inside", "caption-side", "clear", "clip", "color", "color-profile", "column-count", "column-fill", "column-gap", "column-rule", "column-rule-color", "column-rule-style", "column-rule-width", "column-span", "column-width", "columns", "content", "counter-increment", "counter-reset", "crop", "cue", "cue-after", "cue-before", "cursor", "direction", "display", "dominant-baseline", "drop-initial-after-adjust", "drop-initial-after-align", "drop-initial-before-adjust", "drop-initial-before-align", "drop-initial-size", "drop-initial-value", "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis", "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings", "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-synthesis", "font-variant", "font-variant-alternates", "font-variant-caps", "font-variant-east-asian", "font-variant-ligatures", "font-variant-numeric", "font-variant-position", "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", "grid-auto-position", "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-start", "grid-row", "grid-row-end", "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns", "grid-template-rows", "hanging-punctuation", "height", "hyphens", "icon", "image-orientation", "image-rendering", "image-resolution", "inline-box-align", "justify-content", "left", "letter-spacing", "line-break", "line-height", "line-stacking", "line-stacking-ruby", "line-stacking-shift", "line-stacking-strategy", "list-style", "list-style-image", "list-style-position", "list-style-type", "margin", "margin-bottom", "margin-left", "margin-right", "margin-top", "marker-offset", "marks", "marquee-direction", "marquee-loop", "marquee-play-count", "marquee-speed", "marquee-style", "max-height", "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index", "nav-left", "nav-right", "nav-up", "object-fit", "object-position", "opacity", "order", "orphans", "outline", "outline-color", "outline-offset", "outline-style", "outline-width", "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y", "padding", "padding-bottom", "padding-left", "padding-right", "padding-top", "page", "page-break-after", "page-break-before", "page-break-inside", "page-policy", "pause", "pause-after", "pause-before", "perspective", "perspective-origin", "pitch", "pitch-range", "play-during", "position", "presentation-level", "punctuation-trim", "quotes", "region-break-after", "region-break-before", "region-break-inside", "region-fragment", "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness", "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang", "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin", "shape-outside", "size", "speak", "speak-as", "speak-header", "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set", "tab-size", "table-layout", "target", "target-name", "target-new", "target-position", "text-align", "text-align-last", "text-decoration", "text-decoration-color", "text-decoration-line", "text-decoration-skip", "text-decoration-style", "text-emphasis", "text-emphasis-color", "text-emphasis-position", "text-emphasis-style", "text-height", "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow", "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position", "text-wrap", "top", "transform", "transform-origin", "transform-style", "transition", "transition-delay", "transition-duration", "transition-property", "transition-timing-function", "unicode-bidi", "vertical-align", "visibility", "voice-balance", "voice-duration", "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", "voice-volume", "volume", "white-space", "widows", "width", "word-break", "word-spacing", "word-wrap", "z-index", "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", "color-interpolation", "color-interpolation-filters", "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", "glyph-orientation-vertical", "text-anchor", "writing-mode"],
+        l = b(k),
+        m = ["scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside", "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", "searchfield-results-decoration", "zoom"],
+        n = b(m),
+        o = ["font-family", "src", "unicode-range", "font-variant", "font-feature-settings", "font-stretch", "font-weight", "font-style"],
+        p = b(o),
+        q = ["additive-symbols", "fallback", "negative", "pad", "prefix", "range", "speak-as", "suffix", "symbols", "system"],
+        r = b(q),
+        s = ["aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen"],
+        t = b(s),
+        u = ["above", "absolute", "activeborder", "additive", "activecaption", "afar", "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", "arabic-indic", "armenian", "asterisks", "attr", "auto", "avoid", "avoid-column", "avoid-page", "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary", "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel", "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian", "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch", "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", "col-resize", "collapse", "column", "column-reverse", "compact", "condensed", "contain", "content", "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop", "cross", "crosshair", "currentcolor", "cursive", "cyclic", "dashed", "decimal", "decimal-leading-zero", "default", "default-button", "destination-atop", "destination-in", "destination-out", "destination-over", "devanagari", "disc", "discard", "disclosure-closed", "disclosure-open", "document", "dot-dash", "dot-dot-dash", "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede", "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er", "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et", "ethiopic-halehame-gez", "ethiopic-halehame-om-et", "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", "ethiopic-numeric", "ew-resize", "expanded", "extends", "extra-condensed", "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", "forwards", "from", "geometricPrecision", "georgian", "graytext", "groove", "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew", "help", "hidden", "hide", "higher", "highlight", "highlighttext", "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore", "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", "inline-block", "inline-flex", "inline-table", "inset", "inside", "intrinsic", "invert", "italic", "japanese-formal", "japanese-informal", "justify", "kannada", "katakana", "katakana-iroha", "keep-all", "khmer", "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal", "landscape", "lao", "large", "larger", "left", "level", "lighter", "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem", "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", "lower-roman", "lowercase", "ltr", "malayalam", "match", "matrix", "matrix3d", "media-controls-background", "media-current-time-display", "media-fullscreen-button", "media-mute-button", "media-play-button", "media-return-to-realtime-button", "media-rewind-button", "media-seek-back-button", "media-seek-forward-button", "media-slider", "media-sliderthumb", "media-time-remaining-display", "media-volume-slider", "media-volume-slider-container", "media-volume-sliderthumb", "medium", "menu", "menulist", "menulist-button", "menulist-text", "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", "mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize", "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter", "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button", "radial-gradient", "radio", "read-only", "read-write", "read-write-plaintext-only", "rectangle", "region", "relative", "repeat", "repeating-linear-gradient", "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY", "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running", "s-resize", "sans-serif", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "scroll", "scrollbar", "se-resize", "searchfield", "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", "searchfield-results-decoration", "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", "simp-chinese-formal", "simp-chinese-informal", "single", "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal", "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", "small", "small-caps", "small-caption", "smaller", "solid", "somali", "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "spell-out", "square", "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub", "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row", "table-row-group", "tamil", "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai", "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", "trad-chinese-formal", "trad-chinese-informal", "translate", "translate3d", "translateX", "translateY", "translateZ", "transparent", "ultra-condensed", "ultra-expanded", "underline", "up", "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor", "xx-large", "xx-small"],
+        v = b(u),
+        w = c.concat(e)
+        .concat(g)
+        .concat(i)
+        .concat(k)
+        .concat(m)
+        .concat(s)
+        .concat(u);
+    a.registerHelper("hintWords", "css", w), a.defineMIME("text/css", {
+        documentTypes: d,
+        mediaTypes: f,
+        mediaFeatures: h,
+        mediaValueKeywords: j,
+        propertyKeywords: l,
+        nonStandardPropertyKeywords: n,
+        fontProperties: p,
+        counterDescriptors: r,
+        colorKeywords: t,
+        valueKeywords: v,
+        tokenHooks: {
+            "/": function (a, b) {
+                return a.eat("*") ? (b.tokenize = x, x(a, b)) : !1
+            }
+        },
+        name: "css"
+    }), a.defineMIME("text/x-scss", {
+        mediaTypes: f,
+        mediaFeatures: h,
+        mediaValueKeywords: j,
+        propertyKeywords: l,
+        nonStandardPropertyKeywords: n,
+        colorKeywords: t,
+        valueKeywords: v,
+        fontProperties: p,
+        allowNested: !0,
+        tokenHooks: {
+            "/": function (a, b) {
+                return a.eat("/") ? (a.skipToEnd(), ["comment", "comment"]) : a.eat("*") ? (b.tokenize = x, x(a, b)) : ["operator", "operator"]
+            },
+            ":": function (a) {
+                return a.match(/\s*\{/) ? [null, "{"] : !1
+            },
+            $: function (a) {
+                return a.match(/^[\w-]+/), a.match(/^\s*:/, !1) ? ["variable-2", "variable-definition"] : ["variable-2", "variable"]
+            },
+            "#": function (a) {
+                return a.eat("{") ? [null, "interpolation"] : !1
+            }
+        },
+        name: "css",
+        helperType: "scss"
+    }), a.defineMIME("text/x-less", {
+        mediaTypes: f,
+        mediaFeatures: h,
+        mediaValueKeywords: j,
+        propertyKeywords: l,
+        nonStandardPropertyKeywords: n,
+        colorKeywords: t,
+        valueKeywords: v,
+        fontProperties: p,
+        allowNested: !0,
+        tokenHooks: {
+            "/": function (a, b) {
+                return a.eat("/") ? (a.skipToEnd(), ["comment", "comment"]) : a.eat("*") ? (b.tokenize = x, x(a, b)) : ["operator", "operator"]
+            },
+            "@": function (a) {
+                return a.eat("{") ? [null, "interpolation"] : a.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, !1) ? !1 : (a.eatWhile(/[\w\\\-]/), a.match(/^\s*:/, !1) ? ["variable-2", "variable-definition"] : ["variable-2", "variable"])
+            },
+            "&": function () {
+                return ["atom", "atom"]
+            }
+        },
+        name: "css",
+        helperType: "less"
+    }), a.defineMIME("text/x-gss", {
+        documentTypes: d,
+        mediaTypes: f,
+        mediaFeatures: h,
+        propertyKeywords: l,
+        nonStandardPropertyKeywords: n,
+        fontProperties: p,
+        counterDescriptors: r,
+        colorKeywords: t,
+        valueKeywords: v,
+        supportsAtComponent: !0,
+        tokenHooks: {
+            "/": function (a, b) {
+                return a.eat("*") ? (b.tokenize = x, x(a, b)) : !1
+            }
+        },
+        name: "css",
+        helperType: "gss"
+    })
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+
+    function c(a, b, c) {
+        var d = a.current(),
+            e = d.search(b);
+        return e > -1 ? a.backUp(d.length - e) : d.match(/<\/?$/) && (a.backUp(d.length), a.match(b, !1) || a.match(d)), c
+    }
+
+    function e(a) {
+        var b = d[a];
+        return b ? b : d[a] = new RegExp("\\s+" + a + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*")
+    }
+
+    function f(a, b) {
+        for (var d, c = a.pos; c >= 0 && "<" !== a.string.charAt(c);) c--;
+        return 0 > c ? c : (d = a.string.slice(c, a.pos)
+            .match(e(b))) ? d[2] : ""
+    }
+
+    function g(a, b) {
+        return new RegExp((b ? "^" : "") + "</s*" + a + "s*>", "i")
+    }
+
+    function h(a, b) {
+        for (var c in a)
+            for (var d = b[c] || (b[c] = []), e = a[c], f = e.length - 1; f >= 0; f--) d.unshift(e[f])
+    }
+
+    function i(a, b) {
+        for (var c = 0; c < a.length; c++) {
+            var d = a[c];
+            if (!d[0] || d[1].test(f(b, d[0]))) return d[2]
+        }
+    }
+    var b = {
+            script: [["lang", /(javascript|babel)/i, "javascript"], ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i, "javascript"], ["type", /./, "text/plain"], [null, null, "javascript"]],
+            style: [["lang", /^css$/i, "css"], ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"], ["type", /./, "text/plain"], [null, null, "css"]]
+        },
+        d = {};
+    a.defineMode("htmlmixed", function (d, e) {
+        function n(b, e) {
+            var m, h = e.htmlState.tagName,
+                k = h && j[h.toLowerCase()],
+                l = f.token(b, e.htmlState);
+            if (k && /\btag\b/.test(l) && ">" === b.current() && (m = i(k, b))) {
+                var o = a.getMode(d, m),
+                    p = g(h, !0),
+                    q = g(h, !1);
+                e.token = function (a, b) {
+                    return a.match(p, !1) ? (b.token = n, b.localState = b.localMode = null, null) : c(a, q, b.localMode.token(a, b.localState))
+                }, e.localMode = o, e.localState = a.startState(o, f.indent(e.htmlState, ""))
+            }
+            return l
+        }
+        var f = a.getMode(d, {
+                name: "xml",
+                htmlMode: !0,
+                multilineTagIndentFactor: e.multilineTagIndentFactor,
+                multilineTagIndentPastTag: e.multilineTagIndentPastTag
+            }),
+            j = {},
+            k = e && e.tags,
+            l = e && e.scriptTypes;
+        if (h(b, j), k && h(k, j), l)
+            for (var m = l.length - 1; m >= 0; m--) j.script.unshift(["type", l[m].matches, l[m].mode]);
+        return {
+            startState: function () {
+                var a = f.startState();
+                return {
+                    token: n,
+                    localMode: null,
+                    localState: null,
+                    htmlState: a
+                }
+            },
+            copyState: function (b) {
+                var c;
+                return b.localState && (c = a.copyState(b.localMode, b.localState)), {
+                    token: b.token,
+                    localMode: b.localMode,
+                    localState: c,
+                    htmlState: a.copyState(f, b.htmlState)
+                }
+            },
+            token: function (a, b) {
+                return b.token(a, b)
+            },
+            indent: function (b, c) {
+                return !b.localMode || /^\s*<\//.test(c) ? f.indent(b.htmlState, c) : b.localMode.indent ? b.localMode.indent(b.localState, c) : a.Pass
+            },
+            innerMode: function (a) {
+                return {
+                    state: a.localState || a.htmlState,
+                    mode: a.localMode || f
+                }
+            }
+        }
+    }, "xml", "javascript", "css"), a.defineMIME("text/html", "htmlmixed")
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+    a.defineMode("javascript", function (b, c) {
+            function m(a) {
+                for (var c, b = !1, d = !1; null != (c = a.next());) {
+                    if (!b) {
+                        if ("/" == c && !d) return;
+                        "[" == c ? d = !0 : d && "]" == c && (d = !1)
+                    }
+                    b = !b && "\\" == c
+                }
+            }
+
+            function p(a, b, c) {
+                return n = a, o = c, b
+            }
+
+            function q(a, b) {
+                var c = a.next();
+                if ('"' == c || "'" == c) return b.tokenize = r(c), b.tokenize(a, b);
+                if ("." == c && a.match(/^\d+(?:[eE][+\-]?\d+)?/)) return p("number", "number");
+                if ("." == c && a.match("..")) return p("spread", "meta");
+                if (/[\[\]{}\(\),;\:\.]/.test(c)) return p(c);
+                if ("=" == c && a.eat(">")) return p("=>", "operator");
+                if ("0" == c && a.eat(/x/i)) return a.eatWhile(/[\da-f]/i), p("number", "number");
+                if (/\d/.test(c)) return a.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/), p("number", "number");
+                if ("/" == c) return a.eat("*") ? (b.tokenize = s, s(a, b)) : a.eat("/") ? (a.skipToEnd(), p("comment", "comment")) : "operator" == b.lastType || "keyword c" == b.lastType || "sof" == b.lastType || /^[\[{}\(,;:]$/.test(b.lastType) ? (m(a), a.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/), p("regexp", "string-2")) : (a.eatWhile(k), p("operator", "operator", a.current()));
+                if ("`" == c) return b.tokenize = t, t(a, b);
+                if ("#" == c) return a.skipToEnd(), p("error", "error");
+                if (k.test(c)) return a.eatWhile(k), p("operator", "operator", a.current());
+                if (i.test(c)) {
+                    a.eatWhile(i);
+                    var d = a.current(),
+                        e = j.propertyIsEnumerable(d) && j[d];
+                    return e && "." != b.lastType ? p(e.type, e.style, d) : p("variable", "variable", d)
+                }
+            }
+
+            function r(a) {
+                return function (b, c) {
+                    var e, d = !1;
+                    if (f && "@" == b.peek() && b.match(l)) return c.tokenize = q, p("jsonld-keyword", "meta");
+                    for (; null != (e = b.next()) && (e != a || d);) d = !d && "\\" == e;
+                    return d || (c.tokenize = q), p("string", "string")
+                }
+            }
+
+            function s(a, b) {
+                for (var d, c = !1; d = a.next();) {
+                    if ("/" == d && c) {
+                        b.tokenize = q;
+                        break
+                    }
+                    c = "*" == d
+                }
+                return p("comment", "comment")
+            }
+
+            function t(a, b) {
+                for (var d, c = !1; null != (d = a.next());) {
+                    if (!c && ("`" == d || "$" == d && a.eat("{"))) {
+                        b.tokenize = q;
+                        break
+                    }
+                    c = !c && "\\" == d
+                }
+                return p("quasi", "string-2", a.current())
+            }
+
+            function v(a, b) {
+                b.fatArrowAt && (b.fatArrowAt = null);
+                var c = a.string.indexOf("=>", a.start);
+                if (!(0 > c)) {
+                    for (var d = 0, e = !1, f = c - 1; f >= 0; --f) {
+                        var g = a.string.charAt(f),
+                            h = u.indexOf(g);
+                        if (h >= 0 && 3 > h) {
+                            if (!d) {
+                                ++f;
+                                break
+                            }
+                            if (0 == --d) break
+                        } else if (h >= 3 && 6 > h) ++d;
+                        else if (i.test(g)) e = !0;
+                        else {
+                            if (/["'\/]/.test(g)) return;
+                            if (e && !d) {
+                                ++f;
+                                break
+                            }
+                        }
+                    }
+                    e && !d && (b.fatArrowAt = f)
+                }
+            }
+
+            function x(a, b, c, d, e, f) {
+                this.indented = a, this.column = b, this.type = c, this.prev = e, this.info = f, null != d && (this.align = d)
+            }
+
+            function y(a, b) {
+                for (var c = a.localVars; c; c = c.next)
+                    if (c.name == b) return !0;
+                for (var d = a.context; d; d = d.prev)
+                    for (var c = d.vars; c; c = c.next)
+                        if (c.name == b) return !0
+            }
+
+            function z(a, b, c, d, e) {
+                var f = a.cc;
+                for (A.state = a, A.stream = e, A.marked = null, A.cc = f, A.style = b, a.lexical.hasOwnProperty("align") || (a.lexical.align = !0);;) {
+                    var h = f.length ? f.pop() : g ? L : K;
+                    if (h(c, d)) {
+                        for (; f.length && f[f.length - 1].lex;) f.pop()();
+                        return A.marked ? A.marked : "variable" == c && y(a, d) ? "variable-2" : b
+                    }
+                }
+            }
+
+            function B() {
+                for (var a = arguments.length - 1; a >= 0; a--) A.cc.push(arguments[a])
+            }
+
+            function C() {
+                return B.apply(null, arguments), !0
+            }
+
+            function D(a) {
+                function b(b) {
+                    for (var c = b; c; c = c.next)
+                        if (c.name == a) return !0;
+                    return !1
+                }
+                var d = A.state;
+                if (d.context) {
+                    if (A.marked = "def", b(d.localVars)) return;
+                    d.localVars = {
+                        name: a,
+                        next: d.localVars
+                    }
+                } else {
+                    if (b(d.globalVars)) return;
+                    c.globalVars && (d.globalVars = {
+                        name: a,
+                        next: d.globalVars
+                    })
+                }
+            }
+
+            function F() {
+                A.state.context = {
+                    prev: A.state.context,
+                    vars: A.state.localVars
+                }, A.state.localVars = E
+            }
+
+            function G() {
+                A.state.localVars = A.state.context.vars, A.state.context = A.state.context.prev
+            }
+
+            function H(a, b) {
+                var c = function () {
+                    var c = A.state,
+                        d = c.indented;
+                    if ("stat" == c.lexical.type) d = c.lexical.indented;
+                    else
+                        for (var e = c.lexical; e && ")" == e.type && e.align; e = e.prev) d = e.indented;
+                    c.lexical = new x(d, A.stream.column(), a, null, c.lexical, b)
+                };
+                return c.lex = !0, c
+            }
+
+            function I() {
+                var a = A.state;
+                a.lexical.prev && (")" == a.lexical.type && (a.indented = a.lexical.indented), a.lexical = a.lexical.prev)
+            }
+
+            function J(a) {
+                function b(c) {
+                    return c == a ? C() : ";" == a ? B() : C(b)
+                }
+                return b
+            }
+
+            function K(a, b) {
+                return "var" == a ? C(H("vardef", b.length), fa, J(";"), I) : "keyword a" == a ? C(H("form"), L, K, I) : "keyword b" == a ? C(H("form"), K, I) : "{" == a ? C(H("}"), ba, I) : ";" == a ? C() : "if" == a ? ("else" == A.state.lexical.info && A.state.cc[A.state.cc.length - 1] == I && A.state.cc.pop()(), C(H("form"), L, K, I, ka)) : "function" == a ? C(qa) : "for" == a ? C(H("form"), la, K, I) : "variable" == a ? C(H("stat"), W) : "switch" == a ? C(H("form"), L, H("}", "switch"), J("{"), ba, I, I) : "case" == a ? C(L, J(":")) : "default" == a ? C(J(":")) : "catch" == a ? C(H("form"), F, J("("), ra, J(")"), K, I, G) : "class" == a ? C(H("form"), sa, I) : "export" == a ? C(H("form"), wa, I) : "import" == a ? C(H("form"), xa, I) : B(H("stat"), L, J(";"), I)
+            }
+
+            function L(a) {
+                return N(a, !1)
+            }
+
+            function M(a) {
+                return N(a, !0)
+            }
+
+            function N(a, b) {
+                if (A.state.fatArrowAt == A.stream.start) {
+                    var c = b ? V : U;
+                    if ("(" == a) return C(F, H(")"), _(ga, ")"), I, J("=>"), c, G);
+                    if ("variable" == a) return B(F, ga, J("=>"), c, G)
+                }
+                var d = b ? R : Q;
+                return w.hasOwnProperty(a) ? C(d) : "async" == a ? C(L) : "function" == a ? C(qa, d) : "keyword c" == a ? C(b ? P : O) : "(" == a ? C(H(")"), O, Da, J(")"), I, d) : "operator" == a || "spread" == a ? C(b ? M : L) : "[" == a ? C(H("]"), Ba, I, d) : "{" == a ? aa(Y, "}", null, d) : "quasi" == a ? B(S, d) : C()
+            }
+
+            function O(a) {
+                return a.match(/[;\}\)\],]/) ? B() : B(L)
+            }
+
+            function P(a) {
+                return a.match(/[;\}\)\],]/) ? B() : B(M)
+            }
+
+            function Q(a, b) {
+                return "," == a ? C(L) : R(a, b, !1)
+            }
+
+            function R(a, b, c) {
+                var d = 0 == c ? Q : R,
+                    e = 0 == c ? L : M;
+                return "=>" == a ? C(F, c ? V : U, G) : "operator" == a ? /\+\+|--/.test(b) ? C(d) : "?" == b ? C(L, J(":"), e) : C(e) : "quasi" == a ? B(S, d) : ";" != a ? "(" == a ? aa(M, ")", "call", d) : "." == a ? C(X, d) : "[" == a ? C(H("]"), O, J("]"), I, d) : void 0 : void 0
+            }
+
+            function S(a, b) {
+                return "quasi" != a ? B() : "${" != b.slice(b.length - 2) ? C(S) : C(L, T)
+            }
+
+            function T(a) {
+                return "}" == a ? (A.marked = "string-2", A.state.tokenize = t, C(S)) : void 0
+            }
+
+            function U(a) {
+                return v(A.stream, A.state), B("{" == a ? K : L)
+            }
+
+            function V(a) {
+                return v(A.stream, A.state), B("{" == a ? K : M)
+            }
+
+            function W(a) {
+                return ":" == a ? C(I, K) : B(Q, J(";"), I)
+            }
+
+            function X(a) {
+                return "variable" == a ? (A.marked = "property", C()) : void 0
+            }
+
+            function Y(a, b) {
+                return "async" == a ? C(Y) : "variable" == a || "keyword" == A.style ? (A.marked = "property", C("get" == b || "set" == b ? Z : $)) : "number" == a || "string" == a ? (A.marked = f ? "property" : A.style + " property", C($)) : "jsonld-keyword" == a ? C($) : "[" == a ? C(L, J("]"), $) : void 0
+            }
+
+            function Z(a) {
+                return "variable" != a ? B($) : (A.marked = "property", C(qa))
+            }
+
+            function $(a) {
+                return ":" == a ? C(M) : "(" == a ? B(qa) : void 0
+            }
+
+            function _(a, b) {
+                function c(d) {
+                    if ("," == d) {
+                        var e = A.state.lexical;
+                        return "call" == e.info && (e.pos = (e.pos || 0) + 1), C(a, c)
+                    }
+                    return d == b ? C() : C(J(b))
+                }
+                return function (d) {
+                    return d == b ? C() : B(a, c)
+                }
+            }
+
+            function aa(a, b, c) {
+                for (var d = 3; d < arguments.length; d++) A.cc.push(arguments[d]);
+                return C(H(b, c), _(a, b), I)
+            }
+
+            function ba(a) {
+                return "}" == a ? C() : B(K, ba)
+            }
+
+            function ca(a) {
+                return h && ":" == a ? C(ea) : void 0
+            }
+
+            function da(a, b) {
+                return "=" == b ? C(M) : void 0
+            }
+
+            function ea(a) {
+                return "variable" == a ? (A.marked = "variable-3", C()) : void 0
+            }
+
+            function fa() {
+                return B(ga, ca, ia, ja)
+            }
+
+            function ga(a, b) {
+                return "variable" == a ? (D(b), C()) : "[" == a ? aa(ga, "]") : "{" == a ? aa(ha, "}") : void 0
+            }
+
+            function ha(a, b) {
+                return "variable" != a || A.stream.match(/^\s*:/, !1) ? ("variable" == a && (A.marked = "property"), C(J(":"), ga, ia)) : (D(b), C(ia))
+            }
+
+            function ia(a, b) {
+                return "=" == b ? C(M) : void 0
+            }
+
+            function ja(a) {
+                return "," == a ? C(fa) : void 0
+            }
+
+            function ka(a, b) {
+                return "keyword b" == a && "else" == b ? C(H("form", "else"), K, I) : void 0
+            }
+
+            function la(a) {
+                return "(" == a ? C(H(")"), ma, J(")"), I) : void 0
+            }
+
+            function ma(a) {
+                return "var" == a ? C(fa, J(";"), oa) : ";" == a ? C(oa) : "variable" == a ? C(na) : B(L, J(";"), oa)
+            }
+
+            function na(a, b) {
+                return "in" == b || "of" == b ? (A.marked = "keyword", C(L)) : C(Q, oa)
+            }
+
+            function oa(a, b) {
+                return ";" == a ? C(pa) : "in" == b || "of" == b ? (A.marked = "keyword", C(L)) : B(L, J(";"), pa)
+            }
+
+            function pa(a) {
+                ")" != a && C(L)
+            }
+
+            function qa(a, b) {
+                return "*" == b ? (A.marked = "keyword", C(qa)) : "variable" == a ? (D(b), C(qa)) : "(" == a ? C(F, H(")"), _(ra, ")"), I, K, G) : void 0
+            }
+
+            function ra(a) {
+                return "spread" == a ? C(ra) : B(ga, ca, da)
+            }
+
+            function sa(a, b) {
+                return "variable" == a ? (D(b), C(ta)) : void 0
+            }
+
+            function ta(a, b) {
+                return "extends" == b ? C(L, ta) : "{" == a ? C(H("}"), ua, I) : void 0
+            }
+
+            function ua(a, b) {
+                return "variable" == a || "keyword" == A.style ? "static" == b ? (A.marked = "keyword", C(ua)) : (A.marked = "property", "get" == b || "set" == b ? C(va, qa, ua) : C(qa, ua)) : "*" == b ? (A.marked = "keyword", C(ua)) : ";" == a ? C(ua) : "}" == a ? C() : void 0
+            }
+
+            function va(a) {
+                return "variable" != a ? B() : (A.marked = "property", C())
+            }
+
+            function wa(a, b) {
+                return "*" == b ? (A.marked = "keyword", C(Aa, J(";"))) : "default" == b ? (A.marked = "keyword", C(L, J(";"))) : B(K)
+            }
+
+            function xa(a) {
+                return "string" == a ? C() : B(ya, Aa)
+            }
+
+            function ya(a, b) {
+                return "{" == a ? aa(ya, "}") : ("variable" == a && D(b), "*" == b && (A.marked = "keyword"), C(za))
+            }
+
+            function za(a, b) {
+                return "as" == b ? (A.marked = "keyword", C(ya)) : void 0
+            }
+
+            function Aa(a, b) {
+                return "from" == b ? (A.marked = "keyword", C(L)) : void 0
+            }
+
+            function Ba(a) {
+                return "]" == a ? C() : B(M, Ca)
+            }
+
+            function Ca(a) {
+                return "for" == a ? B(Da, J("]")) : "," == a ? C(_(P, "]")) : B(_(M, "]"))
+            }
+
+            function Da(a) {
+                return "for" == a ? C(la, Da) : "if" == a ? C(L, Da) : void 0
+            }
+
+            function Ea(a, b) {
+                return "operator" == a.lastType || "," == a.lastType || k.test(b.charAt(0)) || /[,.]/.test(b.charAt(0))
+            }
+            var n, o, d = b.indentUnit,
+                e = c.statementIndent,
+                f = c.jsonld,
+                g = c.json || f,
+                h = c.typescript,
+                i = c.wordCharacters || /[\w$\xa1-\uffff]/,
+                j = function () {
+                    function a(a) {
+                        return {
+                            type: a,
+                            style: "keyword"
+                        }
+                    }
+                    var b = a("keyword a"),
+                        c = a("keyword b"),
+                        d = a("keyword c"),
+                        e = a("operator"),
+                        f = {
+                            type: "atom",
+                            style: "atom"
+                        },
+                        g = {
+                            "if": a("if"),
+                            "while": b,
+                            "with": b,
+                            "else": c,
+                            "do": c,
+                            "try": c,
+                            "finally": c,
+                            "return": d,
+                            "break": d,
+                            "continue": d,
+                            "new": d,
+                            "delete": d,
+                            "throw": d,
+                            "debugger": d,
+                            "var": a("var"),
+                            "const": a("var"),
+                            let: a("var"),
+                            async: a("async"),
+                            "function": a("function"),
+                            "catch": a("catch"),
+                            "for": a("for"),
+                            "switch": a("switch"),
+                            "case": a("case"),
+                            "default": a("default"),
+                            "in": e,
+                            "typeof": e,
+                            "instanceof": e,
+                            "true": f,
+                            "false": f,
+                            "null": f,
+                            undefined: f,
+                            NaN: f,
+                            Infinity: f,
+                            "this": a("this"),
+                            "class": a("class"),
+                            "super": a("atom"),
+                            await: d,
+                            "yield": d,
+                            "export": a("export"),
+                            "import": a("import"),
+                            "extends": d
+                        };
+                    if (h) {
+                        var i = {
+                                type: "variable",
+                                style: "variable-3"
+                            },
+                            j = {
+                                "interface": a("interface"),
+                                "extends": a("extends"),
+                                constructor: a("constructor"),
+                                "public": a("public"),
+                                "private": a("private"),
+                                "protected": a("protected"),
+                                "static": a("static"),
+                                string: i,
+                                number: i,
+                                bool: i,
+                                any: i
+                            };
+                        for (var k in j) g[k] = j[k]
+                    }
+                    return g
+                }(),
+                k = /[+\-*&%=<>!?|~^]/,
+                l = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/,
+                u = "([{}])",
+                w = {
+                    atom: !0,
+                    number: !0,
+                    variable: !0,
+                    string: !0,
+                    regexp: !0,
+                    "this": !0,
+                    "jsonld-keyword": !0
+                },
+                A = {
+                    state: null,
+                    column: null,
+                    marked: null,
+                    cc: null
+                },
+                E = {
+                    name: "this",
+                    next: {
+                        name: "arguments"
+                    }
+                };
+            return I.lex = !0, {
+                startState: function (a) {
+                    var b = {
+                        tokenize: q,
+                        lastType: "sof",
+                        cc: [],
+                        lexical: new x((a || 0) - d, 0, "block", !1),
+                        localVars: c.localVars,
+                        context: c.localVars && {
+                            vars: c.localVars
+                        },
+                        indented: 0
+                    };
+                    return c.globalVars && "object" == typeof c.globalVars && (b.globalVars = c.globalVars), b
+                },
+                token: function (a, b) {
+                    if (a.sol() && (b.lexical.hasOwnProperty("align") || (b.lexical.align = !1), b.indented = a.indentation(), v(a, b)), b.tokenize != s && a.eatSpace()) return null;
+                    var c = b.tokenize(a, b);
+                    return "comment" == n ? c : (b.lastType = "operator" != n || "++" != o && "--" != o ? n : "incdec", z(b, c, n, o, a))
+                },
+                indent: function (b, f) {
+                    if (b.tokenize == s) return a.Pass;
+                    if (b.tokenize != q) return 0;
+                    var g = f && f.charAt(0),
+                        h = b.lexical;
+                    if (!/^\s*else\b/.test(f))
+                        for (var i = b.cc.length - 1; i >= 0; --i) {
+                            var j = b.cc[i];
+                            if (j == I) h = h.prev;
+                            else if (j != ka) break
+                        }
+                    "stat" == h.type && "}" == g && (h = h.prev), e && ")" == h.type && "stat" == h.prev.type && (h = h.prev);
+                    var k = h.type,
+                        l = g == k;
+                    return "vardef" == k ? h.indented + ("operator" == b.lastType || "," == b.lastType ? h.info + 1 : 0) : "form" == k && "{" == g ? h.indented : "form" == k ? h.indented + d : "stat" == k ? h.indented + (Ea(b, f) ? e || d : 0) : "switch" != h.info || l || 0 == c.doubleIndentSwitch ? h.align ? h.column + (l ? 0 : 1) : h.indented + (l ? 0 : d) : h.indented + (/^(?:case|default)\b/.test(f) ? d : 2 * d)
+                },
+                electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
+                blockCommentStart: g ? null : "/*",
+                blockCommentEnd: g ? null : "*/",
+                lineComment: g ? null : "//",
+                fold: "brace",
+                closeBrackets: "()[]{}''\"\"``",
+                helperType: g ? "json" : "javascript",
+                jsonldMode: f,
+                jsonMode: g
+            }
+        }), a.registerHelper("wordChars", "javascript", /[\w$]/), a.defineMIME("text/javascript", "javascript"), a.defineMIME("text/ecmascript", "javascript"), a.defineMIME("application/javascript", "javascript"),
+        a.defineMIME("application/x-javascript", "javascript"), a.defineMIME("application/ecmascript", "javascript"), a.defineMIME("application/json", {
+            name: "javascript",
+            json: !0
+        }), a.defineMIME("application/x-json", {
+            name: "javascript",
+            json: !0
+        }), a.defineMIME("application/ld+json", {
+            name: "javascript",
+            jsonld: !0
+        }), a.defineMIME("text/typescript", {
+            name: "javascript",
+            typescript: !0
+        }), a.defineMIME("application/typescript", {
+            name: "javascript",
+            typescript: !0
+        })
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+
+    function b(a, b) {
+        return a.string.charAt(a.pos + (b || 0))
+    }
+
+    function c(a, b) {
+        if (b) {
+            var c = a.pos - b;
+            return a.string.substr(c >= 0 ? c : 0, b)
+        }
+        return a.string.substr(0, a.pos - 1)
+    }
+
+    function d(a, b) {
+        var c = a.string.length,
+            d = c - a.pos + 1;
+        return a.string.substr(a.pos, b && c > b ? b : d)
+    }
+
+    function e(a, b) {
+        var d, c = a.pos + b;
+        0 >= c ? a.pos = 0 : c >= (d = a.string.length - 1) ? a.pos = d : a.pos = c
+    }
+    a.defineMode("perl", function () {
+        function h(a, b, c, d, e) {
+            return b.chain = null, b.style = null, b.tail = null, b.tokenize = function (a, b) {
+                for (var g, f = !1, h = 0; g = a.next();) {
+                    if (g === c[h] && !f) return void 0 !== c[++h] ? (b.chain = c[h], b.style = d, b.tail = e) : e && a.eatWhile(e), b.tokenize = j, d;
+                    f = !f && "\\" == g
+                }
+                return d
+            }, b.tokenize(a, b)
+        }
+
+        function i(a, b, c) {
+            return b.tokenize = function (a, b) {
+                return a.string == c && (b.tokenize = j), a.skipToEnd(), "string"
+            }, b.tokenize(a, b)
+        }
+
+        function j(j, k) {
+            if (j.eatSpace()) return null;
+            if (k.chain) return h(j, k, k.chain, k.style, k.tail);
+            if (j.match(/^\-?[\d\.]/, !1) && j.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/)) return "number";
+            if (j.match(/^<<(?=\w)/)) return j.eatWhile(/\w/), i(j, k, j.current()
+                .substr(2));
+            if (j.sol() && j.match(/^\=item(?!\w)/)) return i(j, k, "=cut");
+            var l = j.next();
+            if ('"' == l || "'" == l) {
+                if (c(j, 3) == "<<" + l) {
+                    var m = j.pos;
+                    j.eatWhile(/\w/);
+                    var n = j.current()
+                        .substr(1);
+                    if (n && j.eat(l)) return i(j, k, n);
+                    j.pos = m
+                }
+                return h(j, k, [l], "string")
+            }
+            if ("q" == l) {
+                var o = b(j, -2);
+                if (!o || !/\w/.test(o))
+                    if (o = b(j, 0), "x" == o) {
+                        if (o = b(j, 1), "(" == o) return e(j, 2), h(j, k, [")"], f, g);
+                        if ("[" == o) return e(j, 2), h(j, k, ["]"], f, g);
+                        if ("{" == o) return e(j, 2), h(j, k, ["}"], f, g);
+                        if ("<" == o) return e(j, 2), h(j, k, [">"], f, g);
+                        if (/[\^'"!~\/]/.test(o)) return e(j, 1), h(j, k, [j.eat(o)], f, g)
+                    } else if ("q" == o) {
+                    if (o = b(j, 1), "(" == o) return e(j, 2), h(j, k, [")"], "string");
+                    if ("[" == o) return e(j, 2), h(j, k, ["]"], "string");
+                    if ("{" == o) return e(j, 2), h(j, k, ["}"], "string");
+                    if ("<" == o) return e(j, 2), h(j, k, [">"], "string");
+                    if (/[\^'"!~\/]/.test(o)) return e(j, 1), h(j, k, [j.eat(o)], "string")
+                } else if ("w" == o) {
+                    if (o = b(j, 1), "(" == o) return e(j, 2), h(j, k, [")"], "bracket");
+                    if ("[" == o) return e(j, 2), h(j, k, ["]"], "bracket");
+                    if ("{" == o) return e(j, 2), h(j, k, ["}"], "bracket");
+                    if ("<" == o) return e(j, 2), h(j, k, [">"], "bracket");
+                    if (/[\^'"!~\/]/.test(o)) return e(j, 1), h(j, k, [j.eat(o)], "bracket")
+                } else if ("r" == o) {
+                    if (o = b(j, 1), "(" == o) return e(j, 2), h(j, k, [")"], f, g);
+                    if ("[" == o) return e(j, 2), h(j, k, ["]"], f, g);
+                    if ("{" == o) return e(j, 2), h(j, k, ["}"], f, g);
+                    if ("<" == o) return e(j, 2), h(j, k, [">"], f, g);
+                    if (/[\^'"!~\/]/.test(o)) return e(j, 1), h(j, k, [j.eat(o)], f, g)
+                } else if (/[\^'"!~\/(\[{<]/.test(o)) {
+                    if ("(" == o) return e(j, 1), h(j, k, [")"], "string");
+                    if ("[" == o) return e(j, 1), h(j, k, ["]"], "string");
+                    if ("{" == o) return e(j, 1), h(j, k, ["}"], "string");
+                    if ("<" == o) return e(j, 1), h(j, k, [">"], "string");
+                    if (/[\^'"!~\/]/.test(o)) return h(j, k, [j.eat(o)], "string")
+                }
+            }
+            if ("m" == l) {
+                var o = b(j, -2);
+                if ((!o || !/\w/.test(o)) && (o = j.eat(/[(\[{<\^'"!~\/]/))) {
+                    if (/[\^'"!~\/]/.test(o)) return h(j, k, [o], f, g);
+                    if ("(" == o) return h(j, k, [")"], f, g);
+                    if ("[" == o) return h(j, k, ["]"], f, g);
+                    if ("{" == o) return h(j, k, ["}"], f, g);
+                    if ("<" == o) return h(j, k, [">"], f, g)
+                }
+            }
+            if ("s" == l) {
+                var o = /[\/>\]})\w]/.test(b(j, -2));
+                if (!o && (o = j.eat(/[(\[{<\^'"!~\/]/))) return "[" == o ? h(j, k, ["]", "]"], f, g) : "{" == o ? h(j, k, ["}", "}"], f, g) : "<" == o ? h(j, k, [">", ">"], f, g) : "(" == o ? h(j, k, [")", ")"], f, g) : h(j, k, [o, o], f, g)
+            }
+            if ("y" == l) {
+                var o = /[\/>\]})\w]/.test(b(j, -2));
+                if (!o && (o = j.eat(/[(\[{<\^'"!~\/]/))) return "[" == o ? h(j, k, ["]", "]"], f, g) : "{" == o ? h(j, k, ["}", "}"], f, g) : "<" == o ? h(j, k, [">", ">"], f, g) : "(" == o ? h(j, k, [")", ")"], f, g) : h(j, k, [o, o], f, g)
+            }
+            if ("t" == l) {
+                var o = /[\/>\]})\w]/.test(b(j, -2));
+                if (!o && (o = j.eat("r"), o && (o = j.eat(/[(\[{<\^'"!~\/]/)))) return "[" == o ? h(j, k, ["]", "]"], f, g) : "{" == o ? h(j, k, ["}", "}"], f, g) : "<" == o ? h(j, k, [">", ">"], f, g) : "(" == o ? h(j, k, [")", ")"], f, g) : h(j, k, [o, o], f, g)
+            }
+            if ("`" == l) return h(j, k, [l], "variable-2");
+            if ("/" == l) return /~\s*$/.test(c(j)) ? h(j, k, [l], f, g) : "operator";
+            if ("$" == l) {
+                var m = j.pos;
+                if (j.eatWhile(/\d/) || j.eat("{") && j.eatWhile(/\d/) && j.eat("}")) return "variable-2";
+                j.pos = m
+            }
+            if (/[$@%]/.test(l)) {
+                var m = j.pos;
+                if (j.eat("^") && j.eat(/[A-Z]/) || !/[@$%&]/.test(b(j, -2)) && j.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)) {
+                    var o = j.current();
+                    if (a[o]) return "variable-2"
+                }
+                j.pos = m
+            }
+            if (/[$@%&]/.test(l) && (j.eatWhile(/[\w$\[\]]/) || j.eat("{") && j.eatWhile(/[\w$\[\]]/) && j.eat("}"))) {
+                var o = j.current();
+                return a[o] ? "variable-2" : "variable"
+            }
+            if ("#" == l && "$" != b(j, -2)) return j.skipToEnd(), "comment";
+            if (/[:+\-\^*$&%@=<>!?|\/~\.]/.test(l)) {
+                var m = j.pos;
+                if (j.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/), a[j.current()]) return "operator";
+                j.pos = m
+            }
+            if ("_" == l && 1 == j.pos) {
+                if ("_END__" == d(j, 6)) return h(j, k, ["\x00"], "comment");
+                if ("_DATA__" == d(j, 7)) return h(j, k, ["\x00"], "variable-2");
+                if ("_C__" == d(j, 7)) return h(j, k, ["\x00"], "string")
+            }
+            if (/\w/.test(l)) {
+                var m = j.pos;
+                if ("{" == b(j, -2) && ("}" == b(j, 0) || j.eatWhile(/\w/) && "}" == b(j, 0))) return "string";
+                j.pos = m
+            }
+            if (/[A-Z]/.test(l)) {
+                var p = b(j, -2),
+                    m = j.pos;
+                if (j.eatWhile(/[A-Z_]/), !/[\da-z]/.test(b(j, 0))) {
+                    var o = a[j.current()];
+                    return o ? (o[1] && (o = o[0]), ":" != p ? 1 == o ? "keyword" : 2 == o ? "def" : 3 == o ? "atom" : 4 == o ? "operator" : 5 == o ? "variable-2" : "meta" : "meta") : "meta"
+                }
+                j.pos = m
+            }
+            if (/[a-zA-Z_]/.test(l)) {
+                var p = b(j, -2);
+                j.eatWhile(/\w/);
+                var o = a[j.current()];
+                return o ? (o[1] && (o = o[0]), ":" != p ? 1 == o ? "keyword" : 2 == o ? "def" : 3 == o ? "atom" : 4 == o ? "operator" : 5 == o ? "variable-2" : "meta" : "meta") : "meta"
+            }
+            return null
+        }
+        var a = {
+                "->": 4,
+                "++": 4,
+                "--": 4,
+                "**": 4,
+                "=~": 4,
+                "!~": 4,
+                "*": 4,
+                "/": 4,
+                "%": 4,
+                x: 4,
+                "+": 4,
+                "-": 4,
+                ".": 4,
+                "<<": 4,
+                ">>": 4,
+                "<": 4,
+                ">": 4,
+                "<=": 4,
+                ">=": 4,
+                lt: 4,
+                gt: 4,
+                le: 4,
+                ge: 4,
+                "==": 4,
+                "!=": 4,
+                "<=>": 4,
+                eq: 4,
+                ne: 4,
+                cmp: 4,
+                "~~": 4,
+                "&": 4,
+                "|": 4,
+                "^": 4,
+                "&&": 4,
+                "||": 4,
+                "//": 4,
+                "..": 4,
+                "...": 4,
+                "?": 4,
+                ":": 4,
+                "=": 4,
+                "+=": 4,
+                "-=": 4,
+                "*=": 4,
+                ",": 4,
+                "=>": 4,
+                "::": 4,
+                not: 4,
+                and: 4,
+                or: 4,
+                xor: 4,
+                BEGIN: [5, 1],
+                END: [5, 1],
+                PRINT: [5, 1],
+                PRINTF: [5, 1],
+                GETC: [5, 1],
+                READ: [5, 1],
+                READLINE: [5, 1],
+                DESTROY: [5, 1],
+                TIE: [5, 1],
+                TIEHANDLE: [5, 1],
+                UNTIE: [5, 1],
+                STDIN: 5,
+                STDIN_TOP: 5,
+                STDOUT: 5,
+                STDOUT_TOP: 5,
+                STDERR: 5,
+                STDERR_TOP: 5,
+                $ARG: 5,
+                $_: 5,
+                "@ARG": 5,
+                "@_": 5,
+                $LIST_SEPARATOR: 5,
+                '$"': 5,
+                $PROCESS_ID: 5,
+                $PID: 5,
+                $$: 5,
+                $REAL_GROUP_ID: 5,
+                $GID: 5,
+                "$(": 5,
+                $EFFECTIVE_GROUP_ID: 5,
+                $EGID: 5,
+                "$)": 5,
+                $PROGRAM_NAME: 5,
+                $0: 5,
+                $SUBSCRIPT_SEPARATOR: 5,
+                $SUBSEP: 5,
+                "$;": 5,
+                $REAL_USER_ID: 5,
+                $UID: 5,
+                "$<": 5,
+                $EFFECTIVE_USER_ID: 5,
+                $EUID: 5,
+                "$>": 5,
+                $a: 5,
+                $b: 5,
+                $COMPILING: 5,
+                "$^C": 5,
+                $DEBUGGING: 5,
+                "$^D": 5,
+                "${^ENCODING}": 5,
+                $ENV: 5,
+                "%ENV": 5,
+                $SYSTEM_FD_MAX: 5,
+                "$^F": 5,
+                "@F": 5,
+                "${^GLOBAL_PHASE}": 5,
+                "$^H": 5,
+                "%^H": 5,
+                "@INC": 5,
+                "%INC": 5,
+                $INPLACE_EDIT: 5,
+                "$^I": 5,
+                "$^M": 5,
+                $OSNAME: 5,
+                "$^O": 5,
+                "${^OPEN}": 5,
+                $PERLDB: 5,
+                "$^P": 5,
+                $SIG: 5,
+                "%SIG": 5,
+                $BASETIME: 5,
+                "$^T": 5,
+                "${^TAINT}": 5,
+                "${^UNICODE}": 5,
+                "${^UTF8CACHE}": 5,
+                "${^UTF8LOCALE}": 5,
+                $PERL_VERSION: 5,
+                "$^V": 5,
+                "${^WIN32_SLOPPY_STAT}": 5,
+                $EXECUTABLE_NAME: 5,
+                "$^X": 5,
+                $1: 5,
+                $MATCH: 5,
+                "$&": 5,
+                "${^MATCH}": 5,
+                $PREMATCH: 5,
+                "$`": 5,
+                "${^PREMATCH}": 5,
+                $POSTMATCH: 5,
+                "$'": 5,
+                "${^POSTMATCH}": 5,
+                $LAST_PAREN_MATCH: 5,
+                "$+": 5,
+                $LAST_SUBMATCH_RESULT: 5,
+                "$^N": 5,
+                "@LAST_MATCH_END": 5,
+                "@+": 5,
+                "%LAST_PAREN_MATCH": 5,
+                "%+": 5,
+                "@LAST_MATCH_START": 5,
+                "@-": 5,
+                "%LAST_MATCH_START": 5,
+                "%-": 5,
+                $LAST_REGEXP_CODE_RESULT: 5,
+                "$^R": 5,
+                "${^RE_DEBUG_FLAGS}": 5,
+                "${^RE_TRIE_MAXBUF}": 5,
+                $ARGV: 5,
+                "@ARGV": 5,
+                ARGV: 5,
+                ARGVOUT: 5,
+                $OUTPUT_FIELD_SEPARATOR: 5,
+                $OFS: 5,
+                "$,": 5,
+                $INPUT_LINE_NUMBER: 5,
+                $NR: 5,
+                "$.": 5,
+                $INPUT_RECORD_SEPARATOR: 5,
+                $RS: 5,
+                "$/": 5,
+                $OUTPUT_RECORD_SEPARATOR: 5,
+                $ORS: 5,
+                "$\\": 5,
+                $OUTPUT_AUTOFLUSH: 5,
+                "$|": 5,
+                $ACCUMULATOR: 5,
+                "$^A": 5,
+                $FORMAT_FORMFEED: 5,
+                "$^L": 5,
+                $FORMAT_PAGE_NUMBER: 5,
+                "$%": 5,
+                $FORMAT_LINES_LEFT: 5,
+                "$-": 5,
+                $FORMAT_LINE_BREAK_CHARACTERS: 5,
+                "$:": 5,
+                $FORMAT_LINES_PER_PAGE: 5,
+                "$=": 5,
+                $FORMAT_TOP_NAME: 5,
+                "$^": 5,
+                $FORMAT_NAME: 5,
+                "$~": 5,
+                "${^CHILD_ERROR_NATIVE}": 5,
+                $EXTENDED_OS_ERROR: 5,
+                "$^E": 5,
+                $EXCEPTIONS_BEING_CAUGHT: 5,
+                "$^S": 5,
+                $WARNING: 5,
+                "$^W": 5,
+                "${^WARNING_BITS}": 5,
+                $OS_ERROR: 5,
+                $ERRNO: 5,
+                "$!": 5,
+                "%OS_ERROR": 5,
+                "%ERRNO": 5,
+                "%!": 5,
+                $CHILD_ERROR: 5,
+                "$?": 5,
+                $EVAL_ERROR: 5,
+                "$@": 5,
+                $OFMT: 5,
+                "$#": 5,
+                "$*": 5,
+                $ARRAY_BASE: 5,
+                "$[": 5,
+                $OLD_PERL_VERSION: 5,
+                "$]": 5,
+                "if": [1, 1],
+                elsif: [1, 1],
+                "else": [1, 1],
+                "while": [1, 1],
+                unless: [1, 1],
+                "for": [1, 1],
+                foreach: [1, 1],
+                abs: 1,
+                accept: 1,
+                alarm: 1,
+                atan2: 1,
+                bind: 1,
+                binmode: 1,
+                bless: 1,
+                bootstrap: 1,
+                "break": 1,
+                caller: 1,
+                chdir: 1,
+                chmod: 1,
+                chomp: 1,
+                chop: 1,
+                chown: 1,
+                chr: 1,
+                chroot: 1,
+                close: 1,
+                closedir: 1,
+                connect: 1,
+                "continue": [1, 1],
+                cos: 1,
+                crypt: 1,
+                dbmclose: 1,
+                dbmopen: 1,
+                "default": 1,
+                defined: 1,
+                "delete": 1,
+                die: 1,
+                "do": 1,
+                dump: 1,
+                each: 1,
+                endgrent: 1,
+                endhostent: 1,
+                endnetent: 1,
+                endprotoent: 1,
+                endpwent: 1,
+                endservent: 1,
+                eof: 1,
+                eval: 1,
+                exec: 1,
+                exists: 1,
+                exit: 1,
+                exp: 1,
+                fcntl: 1,
+                fileno: 1,
+                flock: 1,
+                fork: 1,
+                format: 1,
+                formline: 1,
+                getc: 1,
+                getgrent: 1,
+                getgrgid: 1,
+                getgrnam: 1,
+                gethostbyaddr: 1,
+                gethostbyname: 1,
+                gethostent: 1,
+                getlogin: 1,
+                getnetbyaddr: 1,
+                getnetbyname: 1,
+                getnetent: 1,
+                getpeername: 1,
+                getpgrp: 1,
+                getppid: 1,
+                getpriority: 1,
+                getprotobyname: 1,
+                getprotobynumber: 1,
+                getprotoent: 1,
+                getpwent: 1,
+                getpwnam: 1,
+                getpwuid: 1,
+                getservbyname: 1,
+                getservbyport: 1,
+                getservent: 1,
+                getsockname: 1,
+                getsockopt: 1,
+                given: 1,
+                glob: 1,
+                gmtime: 1,
+                "goto": 1,
+                grep: 1,
+                hex: 1,
+                "import": 1,
+                index: 1,
+                "int": 1,
+                ioctl: 1,
+                join: 1,
+                keys: 1,
+                kill: 1,
+                last: 1,
+                lc: 1,
+                lcfirst: 1,
+                length: 1,
+                link: 1,
+                listen: 1,
+                local: 2,
+                localtime: 1,
+                lock: 1,
+                log: 1,
+                lstat: 1,
+                m: null,
+                map: 1,
+                mkdir: 1,
+                msgctl: 1,
+                msgget: 1,
+                msgrcv: 1,
+                msgsnd: 1,
+                my: 2,
+                "new": 1,
+                next: 1,
+                no: 1,
+                oct: 1,
+                open: 1,
+                opendir: 1,
+                ord: 1,
+                our: 2,
+                pack: 1,
+                "package": 1,
+                pipe: 1,
+                pop: 1,
+                pos: 1,
+                print: 1,
+                printf: 1,
+                prototype: 1,
+                push: 1,
+                q: null,
+                qq: null,
+                qr: null,
+                quotemeta: null,
+                qw: null,
+                qx: null,
+                rand: 1,
+                read: 1,
+                readdir: 1,
+                readline: 1,
+                readlink: 1,
+                readpipe: 1,
+                recv: 1,
+                redo: 1,
+                ref: 1,
+                rename: 1,
+                require: 1,
+                reset: 1,
+                "return": 1,
+                reverse: 1,
+                rewinddir: 1,
+                rindex: 1,
+                rmdir: 1,
+                s: null,
+                say: 1,
+                scalar: 1,
+                seek: 1,
+                seekdir: 1,
+                select: 1,
+                semctl: 1,
+                semget: 1,
+                semop: 1,
+                send: 1,
+                setgrent: 1,
+                sethostent: 1,
+                setnetent: 1,
+                setpgrp: 1,
+                setpriority: 1,
+                setprotoent: 1,
+                setpwent: 1,
+                setservent: 1,
+                setsockopt: 1,
+                shift: 1,
+                shmctl: 1,
+                shmget: 1,
+                shmread: 1,
+                shmwrite: 1,
+                shutdown: 1,
+                sin: 1,
+                sleep: 1,
+                socket: 1,
+                socketpair: 1,
+                sort: 1,
+                splice: 1,
+                split: 1,
+                sprintf: 1,
+                sqrt: 1,
+                srand: 1,
+                stat: 1,
+                state: 1,
+                study: 1,
+                sub: 1,
+                substr: 1,
+                symlink: 1,
+                syscall: 1,
+                sysopen: 1,
+                sysread: 1,
+                sysseek: 1,
+                system: 1,
+                syswrite: 1,
+                tell: 1,
+                telldir: 1,
+                tie: 1,
+                tied: 1,
+                time: 1,
+                times: 1,
+                tr: null,
+                truncate: 1,
+                uc: 1,
+                ucfirst: 1,
+                umask: 1,
+                undef: 1,
+                unlink: 1,
+                unpack: 1,
+                unshift: 1,
+                untie: 1,
+                use: 1,
+                utime: 1,
+                values: 1,
+                vec: 1,
+                wait: 1,
+                waitpid: 1,
+                wantarray: 1,
+                warn: 1,
+                when: 1,
+                write: 1,
+                y: null
+            },
+            f = "string-2",
+            g = /[goseximacplud]/;
+        return {
+            startState: function () {
+                return {
+                    tokenize: j,
+                    chain: null,
+                    style: null,
+                    tail: null
+                }
+            },
+            token: function (a, b) {
+                return (b.tokenize || j)(a, b)
+            },
+            lineComment: "#"
+        }
+    }), a.registerHelper("wordChars", "perl", /[\w$]/), a.defineMIME("text/x-perl", "perl")
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+
+    function b(a) {
+        return new RegExp("^((" + a.join(")|(") + "))\\b")
+    }
+
+    function h(a) {
+        return a.scopes[a.scopes.length - 1]
+    }
+    var c = b(["and", "or", "not", "is"]),
+        d = ["as", "assert", "break", "class", "continue", "def", "del", "elif", "else", "except", "finally", "for", "from", "global", "if", "import", "lambda", "pass", "raise", "return", "try", "while", "with", "yield", "in"],
+        e = ["abs", "all", "any", "bin", "bool", "bytearray", "callable", "chr", "classmethod", "compile", "complex", "delattr", "dict", "dir", "divmod", "enumerate", "eval", "filter", "float", "format", "frozenset", "getattr", "globals", "hasattr", "hash", "help", "hex", "id", "input", "int", "isinstance", "issubclass", "iter", "len", "list", "locals", "map", "max", "memoryview", "min", "next", "object", "oct", "open", "ord", "pow", "property", "range", "repr", "reversed", "round", "set", "setattr", "slice", "sorted", "staticmethod", "str", "sum", "super", "tuple", "type", "vars", "zip", "__import__", "NotImplemented", "Ellipsis", "__debug__"],
+        f = {
+            builtins: ["apply", "basestring", "buffer", "cmp", "coerce", "execfile", "file", "intern", "long", "raw_input", "reduce", "reload", "unichr", "unicode", "xrange", "False", "True", "None"],
+            keywords: ["exec", "print"]
+        },
+        g = {
+            builtins: ["ascii", "bytes", "exec", "print"],
+            keywords: ["nonlocal", "False", "True", "None", "async", "await"]
+        };
+    a.registerHelper("hintWords", "python", d.concat(e)), a.defineMode("python", function (i, j) {
+        function x(a, b) {
+            if (a.sol() && "py" == h(b)
+                .type) {
+                var c = h(b)
+                    .offset;
+                if (a.eatSpace()) {
+                    var d = a.indentation();
+                    return d > c ? A(a, b, "py") : c > d && B(a, b) && (b.errorToken = !0), null
+                }
+                var e = y(a, b);
+                return c > 0 && B(a, b) && (e += " " + k), e
+            }
+            return y(a, b)
+        }
+
+        function y(a, b) {
+            if (a.eatSpace()) return null;
+            var d = a.peek();
+            if ("#" == d) return a.skipToEnd(), "comment";
+            if (a.match(/^[0-9\.]/, !1)) {
+                var e = !1;
+                if (a.match(/^\d*\.\d+(e[\+\-]?\d+)?/i) && (e = !0), a.match(/^\d+\.\d*/) && (e = !0), a.match(/^\.\d+/) && (e = !0), e) return a.eat(/J/i), "number";
+                var f = !1;
+                if (a.match(/^0x[0-9a-f]+/i) && (f = !0), a.match(/^0b[01]+/i) && (f = !0), a.match(/^0o[0-7]+/i) && (f = !0), a.match(/^[1-9]\d*(e[\+\-]?\d+)?/) && (a.eat(/J/i), f = !0), a.match(/^0(?![\dx])/i) && (f = !0), f) return a.eat(/L/i), "number"
+            }
+            return a.match(u) ? (b.tokenize = z(a.current()), b.tokenize(a, b)) : a.match(o) || a.match(n) ? null : a.match(m) || a.match(p) ? "operator" : a.match(l) ? null : a.match(v) || a.match(c) ? "keyword" : a.match(w) ? "builtin" : a.match(/^(self|cls)\b/) ? "variable-2" : a.match(q) ? "def" == b.lastToken || "class" == b.lastToken ? "def" : "variable" : (a.next(), k)
+        }
+
+        function z(a) {
+            function d(d, e) {
+                for (; !d.eol();)
+                    if (d.eatWhile(/[^'"\\]/), d.eat("\\")) {
+                        if (d.next(), b && d.eol()) return c
+                    } else {
+                        if (d.match(a)) return e.tokenize = x, c;
+                        d.eat(/['"]/)
+                    }
+                if (b) {
+                    if (j.singleLineStringErrors) return k;
+                    e.tokenize = x
+                }
+                return c
+            }
+            for (;
+                "rub".indexOf(a.charAt(0)
+                    .toLowerCase()) >= 0;) a = a.substr(1);
+            var b = 1 == a.length,
+                c = "string";
+            return d.isString = !0, d
+        }
+
+        function A(a, b, c) {
+            var d = 0,
+                e = null;
+            if ("py" == c)
+                for (;
+                    "py" != h(b)
+                    .type;) b.scopes.pop();
+            d = h(b)
+                .offset + ("py" == c ? i.indentUnit : r), "py" == c || a.match(/^(\s|#.*)*$/, !1) || (e = a.column() + 1), b.scopes.push({
+                    offset: d,
+                    type: c,
+                    align: e
+                })
+        }
+
+        function B(a, b) {
+            for (var c = a.indentation(); h(b)
+                .offset > c;) {
+                if ("py" != h(b)
+                    .type) return !0;
+                b.scopes.pop()
+            }
+            return h(b)
+                .offset != c
+        }
+
+        function C(a, b) {
+            var c = b.tokenize(a, b),
+                d = a.current();
+            if ("." == d) return c = a.match(q, !1) ? null : k, null == c && "meta" == b.lastStyle && (c = "meta"), c;
+            if ("@" == d) return j.version && 3 == parseInt(j.version, 10) ? a.match(q, !1) ? "meta" : "operator" : a.match(q, !1) ? "meta" : k;
+            "variable" != c && "builtin" != c || "meta" != b.lastStyle || (c = "meta"), ("pass" == d || "return" == d) && (b.dedent += 1), "lambda" == d && (b.lambda = !0), ":" != d || b.lambda || "py" != h(b)
+                .type || A(a, b, "py");
+            var e = 1 == d.length ? "[({".indexOf(d) : -1;
+            if (-1 != e && A(a, b, "])}".slice(e, e + 1)), e = "])}".indexOf(d), -1 != e) {
+                if (h(b)
+                    .type != d) return k;
+                b.scopes.pop()
+            }
+            return b.dedent > 0 && a.eol() && "py" == h(b)
+                .type && (b.scopes.length > 1 && b.scopes.pop(), b.dedent -= 1), c
+        }
+        var k = "error",
+            l = j.singleDelimiters || new RegExp("^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]"),
+            m = j.doubleOperators || new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"),
+            n = j.doubleDelimiters || new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"),
+            o = j.tripleDelimiters || new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
+        if (j.version && 3 == parseInt(j.version, 10)) var p = j.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!@]"),
+            q = j.identifiers || new RegExp("^[_A-Za-z\xa1-\uffff][_A-Za-z0-9\xa1-\uffff]*");
+        else var p = j.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!]"),
+            q = j.identifiers || new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
+        var r = j.hangingIndent || i.indentUnit,
+            s = d,
+            t = e;
+        if (void 0 != j.extra_keywords && (s = s.concat(j.extra_keywords)), void 0 != j.extra_builtins && (t = t.concat(j.extra_builtins)), j.version && 3 == parseInt(j.version, 10)) {
+            s = s.concat(g.keywords), t = t.concat(g.builtins);
+            var u = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i")
+        } else {
+            s = s.concat(f.keywords), t = t.concat(f.builtins);
+            var u = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i")
+        }
+        var v = b(s),
+            w = b(t),
+            D = {
+                startState: function (a) {
+                    return {
+                        tokenize: x,
+                        scopes: [{
+                            offset: a || 0,
+                            type: "py",
+                            align: null
+                        }],
+                        lastStyle: null,
+                        lastToken: null,
+                        lambda: !1,
+                        dedent: 0
+                    }
+                },
+                token: function (a, b) {
+                    var c = b.errorToken;
+                    c && (b.errorToken = !1);
+                    var d = C(a, b);
+                    b.lastStyle = d;
+                    var e = a.current();
+                    return e && d && (b.lastToken = e), a.eol() && b.lambda && (b.lambda = !1), c ? d + " " + k : d
+                },
+                indent: function (b, c) {
+                    if (b.tokenize != x) return b.tokenize.isString ? a.Pass : 0;
+                    var d = h(b),
+                        e = c && c.charAt(0) == d.type;
+                    return null != d.align ? d.align - (e ? 1 : 0) : e && b.scopes.length > 1 ? b.scopes[b.scopes.length - 2].offset : d.offset
+                },
+                closeBrackets: {
+                    triples: "'\""
+                },
+                lineComment: "#",
+                fold: "indent"
+            };
+        return D
+    }), a.defineMIME("text/x-python", "python");
+    var i = function (a) {
+        return a.split(" ")
+    };
+    a.defineMIME("text/x-cython", {
+        name: "python",
+        extra_keywords: i("by cdef cimport cpdef ctypedef enum exceptextern gil include nogil property publicreadonly struct union DEF IF ELIF ELSE")
+    })
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+    a.defineMode("shell", function () {
+        function b(b, c) {
+            for (var d = c.split(" "), e = 0; e < d.length; e++) a[d[e]] = b
+        }
+
+        function c(b, c) {
+            if (b.eatSpace()) return null;
+            var g = b.sol(),
+                h = b.next();
+            if ("\\" === h) return b.next(), null;
+            if ("'" === h || '"' === h || "`" === h) return c.tokens.unshift(d(h)), f(b, c);
+            if ("#" === h) return g && b.eat("!") ? (b.skipToEnd(), "meta") : (b.skipToEnd(), "comment");
+            if ("$" === h) return c.tokens.unshift(e), f(b, c);
+            if ("+" === h || "=" === h) return "operator";
+            if ("-" === h) return b.eat("-"), b.eatWhile(/\w/), "attribute";
+            if (/\d/.test(h) && (b.eatWhile(/\d/), b.eol() || !/\w/.test(b.peek()))) return "number";
+            b.eatWhile(/[\w-]/);
+            var i = b.current();
+            return "=" === b.peek() && /\w+/.test(i) ? "def" : a.hasOwnProperty(i) ? a[i] : null
+        }
+
+        function d(a) {
+            return function (b, c) {
+                for (var d, f = !1, g = !1; null != (d = b.next());) {
+                    if (d === a && !g) {
+                        f = !0;
+                        break
+                    }
+                    if ("$" === d && !g && "'" !== a) {
+                        g = !0, b.backUp(1), c.tokens.unshift(e);
+                        break
+                    }
+                    g = !g && "\\" === d
+                }
+                return (f || !g) && c.tokens.shift(), "`" === a || ")" === a ? "quote" : "string"
+            }
+        }
+
+        function f(a, b) {
+            return (b.tokens[0] || c)(a, b)
+        }
+        var a = {};
+        b("atom", "true false"), b("keyword", "if then do else elif while until for in esac fi fin fil done exit set unset export function"), b("builtin", "ab awk bash beep cat cc cd chown chmod chroot clear cp curl cut diff echo find gawk gcc get git grep kill killall ln ls make mkdir openssl mv nc node npm ping ps restart rm rmdir sed service sh shopt shred source sort sleep ssh start stop su sudo tee telnet top touch vi vim wall wc wget who write yes zsh");
+        var e = function (a, b) {
+            b.tokens.length > 1 && a.eat("$");
+            var c = a.next(),
+                e = /\w/;
+            return "{" === c && (e = /[^}]/), "(" === c ? (b.tokens[0] = d(")"), f(a, b)) : (/\d/.test(c) || (a.eatWhile(e), a.eat("}")), b.tokens.shift(), "def")
+        };
+        return {
+            startState: function () {
+                return {
+                    tokens: []
+                }
+            },
+            token: function (a, b) {
+                return f(a, b)
+            },
+            lineComment: "#",
+            fold: "brace"
+        }
+    }), a.defineMIME("text/x-sh", "shell")
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+    a.defineMode("xml", function (b, c) {
+        function k(a, b) {
+            function c(c) {
+                return b.tokenize = c, c(a, b)
+            }
+            var d = a.next();
+            if ("<" == d) return a.eat("!") ? a.eat("[") ? a.match("CDATA[") ? c(n("atom", "]]>")) : null : a.match("--") ? c(n("comment", "-->")) : a.match("DOCTYPE", !0, !0) ? (a.eatWhile(/[\w\._\-]/), c(o(1))) : null : a.eat("?") ? (a.eatWhile(/[\w\._\-]/), b.tokenize = n("meta", "?>"), "meta") : (i = a.eat("/") ? "closeTag" : "openTag", b.tokenize = l, "tag bracket");
+            if ("&" == d) {
+                var e;
+                return e = a.eat("#") ? a.eat("x") ? a.eatWhile(/[a-fA-F\d]/) && a.eat(";") : a.eatWhile(/[\d]/) && a.eat(";") : a.eatWhile(/[\w\.\-:]/) && a.eat(";"), e ? "atom" : "error"
+            }
+            return a.eatWhile(/[^&<]/), null
+        }
+
+        function l(a, b) {
+            var c = a.next();
+            if (">" == c || "/" == c && a.eat(">")) return b.tokenize = k, i = ">" == c ? "endTag" : "selfcloseTag", "tag bracket";
+            if ("=" == c) return i = "equals", null;
+            if ("<" == c) {
+                b.tokenize = k, b.state = s, b.tagName = b.tagStart = null;
+                var d = b.tokenize(a, b);
+                return d ? d + " tag error" : "tag error"
+            }
+            return /[\'\"]/.test(c) ? (b.tokenize = m(c), b.stringStartCol = a.column(), b.tokenize(a, b)) : (a.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/), "word")
+        }
+
+        function m(a) {
+            var b = function (b, c) {
+                for (; !b.eol();)
+                    if (b.next() == a) {
+                        c.tokenize = l;
+                        break
+                    }
+                return "string"
+            };
+            return b.isInAttribute = !0, b
+        }
+
+        function n(a, b) {
+            return function (c, d) {
+                for (; !c.eol();) {
+                    if (c.match(b)) {
+                        d.tokenize = k;
+                        break
+                    }
+                    c.next()
+                }
+                return a
+            }
+        }
+
+        function o(a) {
+            return function (b, c) {
+                for (var d; null != (d = b.next());) {
+                    if ("<" == d) return c.tokenize = o(a + 1), c.tokenize(b, c);
+                    if (">" == d) {
+                        if (1 == a) {
+                            c.tokenize = k;
+                            break
+                        }
+                        return c.tokenize = o(a - 1), c.tokenize(b, c)
+                    }
+                }
+                return "meta"
+            }
+        }
+
+        function p(a, b, c) {
+            this.prev = a.context, this.tagName = b, this.indent = a.indented, this.startOfLine = c, (g.doNotIndent.hasOwnProperty(b) || a.context && a.context.noIndent) && (this.noIndent = !0)
+        }
+
+        function q(a) {
+            a.context && (a.context = a.context.prev)
+        }
+
+        function r(a, b) {
+            for (var c;;) {
+                if (!a.context) return;
+                if (c = a.context.tagName, !g.contextGrabbers.hasOwnProperty(c) || !g.contextGrabbers[c].hasOwnProperty(b)) return;
+                q(a)
+            }
+        }
+
+        function s(a, b, c) {
+            return "openTag" == a ? (c.tagStart = b.column(), t) : "closeTag" == a ? u : s
+        }
+
+        function t(a, b, c) {
+            return "word" == a ? (c.tagName = b.current(), j = "tag", x) : (j = "error", t)
+        }
+
+        function u(a, b, c) {
+            if ("word" == a) {
+                var d = b.current();
+                return c.context && c.context.tagName != d && g.implicitlyClosed.hasOwnProperty(c.context.tagName) && q(c), c.context && c.context.tagName == d ? (j = "tag", v) : (j = "tag error", w)
+            }
+            return j = "error", w
+        }
+
+        function v(a, b, c) {
+            return "endTag" != a ? (j = "error", v) : (q(c), s)
+        }
+
+        function w(a, b, c) {
+            return j = "error", v(a, b, c)
+        }
+
+        function x(a, b, c) {
+            if ("word" == a) return j = "attribute", y;
+            if ("endTag" == a || "selfcloseTag" == a) {
+                var d = c.tagName,
+                    e = c.tagStart;
+                return c.tagName = c.tagStart = null, "selfcloseTag" == a || g.autoSelfClosers.hasOwnProperty(d) ? r(c, d) : (r(c, d), c.context = new p(c, d, e == c.indented)), s
+            }
+            return j = "error", x
+        }
+
+        function y(a, b, c) {
+            return "equals" == a ? z : (g.allowMissing || (j = "error"), x(a, b, c))
+        }
+
+        function z(a, b, c) {
+            return "string" == a ? A : "word" == a && g.allowUnquoted ? (j = "string", x) : (j = "error", x(a, b, c))
+        }
+
+        function A(a, b, c) {
+            return "string" == a ? A : x(a, b, c)
+        }
+        var d = b.indentUnit,
+            e = c.multilineTagIndentFactor || 1,
+            f = c.multilineTagIndentPastTag;
+        null == f && (f = !0);
+        var i, j, g = c.htmlMode ? {
+                autoSelfClosers: {
+                    area: !0,
+                    base: !0,
+                    br: !0,
+                    col: !0,
+                    command: !0,
+                    embed: !0,
+                    frame: !0,
+                    hr: !0,
+                    img: !0,
+                    input: !0,
+                    keygen: !0,
+                    link: !0,
+                    meta: !0,
+                    param: !0,
+                    source: !0,
+                    track: !0,
+                    wbr: !0,
+                    menuitem: !0
+                },
+                implicitlyClosed: {
+                    dd: !0,
+                    li: !0,
+                    optgroup: !0,
+                    option: !0,
+                    p: !0,
+                    rp: !0,
+                    rt: !0,
+                    tbody: !0,
+                    td: !0,
+                    tfoot: !0,
+                    th: !0,
+                    tr: !0
+                },
+                contextGrabbers: {
+                    dd: {
+                        dd: !0,
+                        dt: !0
+                    },
+                    dt: {
+                        dd: !0,
+                        dt: !0
+                    },
+                    li: {
+                        li: !0
+                    },
+                    option: {
+                        option: !0,
+                        optgroup: !0
+                    },
+                    optgroup: {
+                        optgroup: !0
+                    },
+                    p: {
+                        address: !0,
+                        article: !0,
+                        aside: !0,
+                        blockquote: !0,
+                        dir: !0,
+                        div: !0,
+                        dl: !0,
+                        fieldset: !0,
+                        footer: !0,
+                        form: !0,
+                        h1: !0,
+                        h2: !0,
+                        h3: !0,
+                        h4: !0,
+                        h5: !0,
+                        h6: !0,
+                        header: !0,
+                        hgroup: !0,
+                        hr: !0,
+                        menu: !0,
+                        nav: !0,
+                        ol: !0,
+                        p: !0,
+                        pre: !0,
+                        section: !0,
+                        table: !0,
+                        ul: !0
+                    },
+                    rp: {
+                        rp: !0,
+                        rt: !0
+                    },
+                    rt: {
+                        rp: !0,
+                        rt: !0
+                    },
+                    tbody: {
+                        tbody: !0,
+                        tfoot: !0
+                    },
+                    td: {
+                        td: !0,
+                        th: !0
+                    },
+                    tfoot: {
+                        tbody: !0
+                    },
+                    th: {
+                        td: !0,
+                        th: !0
+                    },
+                    thead: {
+                        tbody: !0,
+                        tfoot: !0
+                    },
+                    tr: {
+                        tr: !0
+                    }
+                },
+                doNotIndent: {
+                    pre: !0
+                },
+                allowUnquoted: !0,
+                allowMissing: !0,
+                caseFold: !0
+            } : {
+                autoSelfClosers: {},
+                implicitlyClosed: {},
+                contextGrabbers: {},
+                doNotIndent: {},
+                allowUnquoted: !1,
+                allowMissing: !1,
+                caseFold: !1
+            },
+            h = c.alignCDATA;
+        return k.isInText = !0, {
+            startState: function () {
+                return {
+                    tokenize: k,
+                    state: s,
+                    indented: 0,
+                    tagName: null,
+                    tagStart: null,
+                    context: null
+                }
+            },
+            token: function (a, b) {
+                if (!b.tagName && a.sol() && (b.indented = a.indentation()), a.eatSpace()) return null;
+                i = null;
+                var c = b.tokenize(a, b);
+                return (c || i) && "comment" != c && (j = null, b.state = b.state(i || c, a, b), j && (c = "error" == j ? c + " error" : j)), c
+            },
+            indent: function (b, c, i) {
+                var j = b.context;
+                if (b.tokenize.isInAttribute) return b.tagStart == b.indented ? b.stringStartCol + 1 : b.indented + d;
+                if (j && j.noIndent) return a.Pass;
+                if (b.tokenize != l && b.tokenize != k) return i ? i.match(/^(\s*)/)[0].length : 0;
+                if (b.tagName) return f ? b.tagStart + b.tagName.length + 2 : b.tagStart + d * e;
+                if (h && /<!\[CDATA\[/.test(c)) return 0;
+                var m = c && /^<(\/)?([\w_:\.-]*)/.exec(c);
+                if (m && m[1])
+                    for (; j;) {
+                        if (j.tagName == m[2]) {
+                            j = j.prev;
+                            break
+                        }
+                        if (!g.implicitlyClosed.hasOwnProperty(j.tagName)) break;
+                        j = j.prev
+                    } else if (m)
+                        for (; j;) {
+                            var n = g.contextGrabbers[j.tagName];
+                            if (!n || !n.hasOwnProperty(m[2])) break;
+                            j = j.prev
+                        }
+                    for (; j && !j.startOfLine;) j = j.prev;
+                return j ? j.indent + d : 0
+            },
+            electricInput: /<\/[\s\w:]+>$/,
+            blockCommentStart: "<!--",
+            blockCommentEnd: "-->",
+            configuration: c.htmlMode ? "html" : "xml",
+            helperType: c.htmlMode ? "html" : "xml"
+        }
+    }), a.defineMIME("text/xml", "xml"), a.defineMIME("application/xml", "xml"), a.mimeModes.hasOwnProperty("text/html") || a.defineMIME("text/html", {
+        name: "xml",
+        htmlMode: !0
+    })
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+
+    function d(a) {
+        for (var d = 0; d < a.state.activeLines.length; d++) a.removeLineClass(a.state.activeLines[d], "wrap", b), a.removeLineClass(a.state.activeLines[d], "background", c)
+    }
+
+    function e(a, b) {
+        if (a.length != b.length) return !1;
+        for (var c = 0; c < a.length; c++)
+            if (a[c] != b[c]) return !1;
+        return !0
+    }
+
+    function f(a, f) {
+        for (var g = [], h = 0; h < f.length; h++) {
+            var i = f[h];
+            if (i.empty()) {
+                var j = a.getLineHandleVisualStart(i.head.line);
+                g[g.length - 1] != j && g.push(j)
+            }
+        }
+        e(a.state.activeLines, g) || a.operation(function () {
+            d(a);
+            for (var e = 0; e < g.length; e++) a.addLineClass(g[e], "wrap", b), a.addLineClass(g[e], "background", c);
+            a.state.activeLines = g
+        })
+    }
+
+    function g(a, b) {
+        f(a, b.ranges)
+    }
+    var b = "CodeMirror-activeline",
+        c = "CodeMirror-activeline-background";
+    a.defineOption("styleActiveLine", !1, function (b, c, e) {
+        var h = e && e != a.Init;
+        c && !h ? (b.state.activeLines = [], f(b, b.listSelections()), b.on("beforeSelectionChange", g)) : !c && h && (b.off("beforeSelectionChange", g), d(b), delete b.state.activeLines)
+    })
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+    a.registerHelper("fold", "brace", function (b, c) {
+        function h(f) {
+            for (var h = c.ch, i = 0;;) {
+                var j = 0 >= h ? -1 : e.lastIndexOf(f, h - 1);
+                if (-1 != j) {
+                    if (1 == i && j < c.ch) break;
+                    if (g = b.getTokenTypeAt(a.Pos(d, j + 1)), !/^(comment|string)/.test(g)) return j + 1;
+                    h = j - 1
+                } else {
+                    if (1 == i) break;
+                    i = 1, h = e.length
+                }
+            }
+        }
+        var f, g, d = c.line,
+            e = b.getLine(d),
+            i = "{",
+            j = "}",
+            f = h("{");
+        if (null == f && (i = "[", j = "]", f = h("[")), null != f) {
+            var m, n, k = 1,
+                l = b.lastLine();
+            a: for (var o = d; l >= o; ++o)
+                for (var p = b.getLine(o), q = o == d ? f : 0;;) {
+                    var r = p.indexOf(i, q),
+                        s = p.indexOf(j, q);
+                    if (0 > r && (r = p.length), 0 > s && (s = p.length), q = Math.min(r, s), q == p.length) break;
+                    if (b.getTokenTypeAt(a.Pos(o, q + 1)) == g)
+                        if (q == r) ++k;
+                        else if (!--k) {
+                        m = o, n = q;
+                        break a
+                    }++q
+                }
+            if (null != m && (d != m || n != f)) return {
+                from: a.Pos(d, f),
+                to: a.Pos(m, n)
+            }
+        }
+    }), a.registerHelper("fold", "import", function (b, c) {
+        function d(c) {
+            if (c < b.firstLine() || c > b.lastLine()) return null;
+            var d = b.getTokenAt(a.Pos(c, 1));
+            if (/\S/.test(d.string) || (d = b.getTokenAt(a.Pos(c, d.end + 1))), "keyword" != d.type || "import" != d.string) return null;
+            for (var e = c, f = Math.min(b.lastLine(), c + 10); f >= e; ++e) {
+                var g = b.getLine(e),
+                    h = g.indexOf(";");
+                if (-1 != h) return {
+                    startCh: d.end,
+                    end: a.Pos(e, h)
+                }
+            }
+        }
+        var f, c = c.line,
+            e = d(c);
+        if (!e || d(c - 1) || (f = d(c - 2)) && f.end.line == c - 1) return null;
+        for (var g = e.end;;) {
+            var h = d(g.line + 1);
+            if (null == h) break;
+            g = h.end
+        }
+        return {
+            from: b.clipPos(a.Pos(c, e.startCh + 1)),
+            to: g
+        }
+    }), a.registerHelper("fold", "include", function (b, c) {
+        function d(c) {
+            if (c < b.firstLine() || c > b.lastLine()) return null;
+            var d = b.getTokenAt(a.Pos(c, 1));
+            return /\S/.test(d.string) || (d = b.getTokenAt(a.Pos(c, d.end + 1))), "meta" == d.type && "#include" == d.string.slice(0, 8) ? d.start + 8 : void 0
+        }
+        var c = c.line,
+            e = d(c);
+        if (null == e || null != d(c - 1)) return null;
+        for (var f = c;;) {
+            var g = d(f + 1);
+            if (null == g) break;
+            ++f
+        }
+        return {
+            from: a.Pos(c, e + 1),
+            to: b.clipPos(a.Pos(f))
+        }
+    })
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    function d(a, c) {
+        return "pairs" == c && "string" == typeof a ? a : "object" == typeof a && null != a[c] ? a[c] : b[c]
+    }
+
+    function h(a) {
+        return function (b) {
+            return l(b, a)
+        }
+    }
+
+    function i(a) {
+        var b = a.state.closeBrackets;
+        if (!b) return null;
+        var c = a.getModeAt(a.getCursor());
+        return c.closeBrackets || b
+    }
+
+    function j(b) {
+        var e = i(b);
+        if (!e || b.getOption("disableInput")) return a.Pass;
+        for (var f = d(e, "pairs"), g = b.listSelections(), h = 0; h < g.length; h++) {
+            if (!g[h].empty()) return a.Pass;
+            var j = n(b, g[h].head);
+            if (!j || f.indexOf(j) % 2 != 0) return a.Pass
+        }
+        for (var h = g.length - 1; h >= 0; h--) {
+            var k = g[h].head;
+            b.replaceRange("", c(k.line, k.ch - 1), c(k.line, k.ch + 1))
+        }
+    }
+
+    function k(b) {
+        var c = i(b),
+            e = c && d(c, "explode");
+        if (!e || b.getOption("disableInput")) return a.Pass;
+        for (var f = b.listSelections(), g = 0; g < f.length; g++) {
+            if (!f[g].empty()) return a.Pass;
+            var h = n(b, f[g].head);
+            if (!h || e.indexOf(h) % 2 != 0) return a.Pass
+        }
+        b.operation(function () {
+            b.replaceSelection("\n\n", null), b.execCommand("goCharLeft"), f = b.listSelections();
+            for (var a = 0; a < f.length; a++) {
+                var c = f[a].head.line;
+                b.indentLine(c, null, !0), b.indentLine(c + 1, null, !0)
+            }
+        })
+    }
+
+    function l(b, e) {
+        var f = i(b);
+        if (!f || b.getOption("disableInput")) return a.Pass;
+        var g = d(f, "pairs"),
+            h = g.indexOf(e);
+        if (-1 == h) return a.Pass;
+        for (var p, q, j = d(f, "triples"), k = g.charAt(h + 1) == e, l = b.listSelections(), n = h % 2 == 0, r = 0; r < l.length; r++) {
+            var u, s = l[r],
+                t = s.head,
+                q = b.getRange(t, c(t.line, t.ch + 1));
+            if (n && !s.empty()) u = "surround";
+            else if (!k && n || q != e)
+                if (k && t.ch > 1 && j.indexOf(e) >= 0 && b.getRange(c(t.line, t.ch - 2), t) == e + e && (t.ch <= 2 || b.getRange(c(t.line, t.ch - 3), c(t.line, t.ch - 2)) != e)) u = "addFour";
+                else if (k) {
+                if (a.isWordChar(q) || !o(b, t, e)) return a.Pass;
+                u = "both"
+            } else {
+                if (!n || b.getLine(t.line)
+                    .length != t.ch && !m(q, g) && !/\s/.test(q)) return a.Pass;
+                u = "both"
+            } else u = j.indexOf(e) >= 0 && b.getRange(t, c(t.line, t.ch + 3)) == e + e + e ? "skipThree" : "skip";
+            if (p) {
+                if (p != u) return a.Pass
+            } else p = u
+        }
+        var v = h % 2 ? g.charAt(h - 1) : e,
+            w = h % 2 ? e : g.charAt(h + 1);
+        b.operation(function () {
+            if ("skip" == p) b.execCommand("goCharRight");
+            else if ("skipThree" == p)
+                for (var a = 0; 3 > a; a++) b.execCommand("goCharRight");
+            else if ("surround" == p) {
+                for (var c = b.getSelections(), a = 0; a < c.length; a++) c[a] = v + c[a] + w;
+                b.replaceSelections(c, "around")
+            } else "both" == p ? (b.replaceSelection(v + w, null), b.triggerElectric(v + w), b.execCommand("goCharLeft")) : "addFour" == p && (b.replaceSelection(v + v + v + v, "before"), b.execCommand("goCharRight"))
+        })
+    }
+
+    function m(a, b) {
+        var c = b.lastIndexOf(a);
+        return c > -1 && c % 2 == 1
+    }
+
+    function n(a, b) {
+        var d = a.getRange(c(b.line, b.ch - 1), c(b.line, b.ch + 1));
+        return 2 == d.length ? d : null
+    }
+
+    function o(b, c, d) {
+        var e = b.getLine(c.line),
+            f = b.getTokenAt(c);
+        if (/\bstring2?\b/.test(f.type)) return !1;
+        var g = new a.StringStream(e.slice(0, c.ch) + d + e.slice(c.ch), 4);
+        for (g.pos = g.start = f.start;;) {
+            var h = b.getMode()
+                .token(g, f.state);
+            if (g.pos >= c.ch + 1) return /\bstring2?\b/.test(h);
+            g.start = g.pos
+        }
+    }
+    var b = {
+            pairs: "()[]{}''\"\"",
+            triples: "",
+            explode: "[]{}"
+        },
+        c = a.Pos;
+    a.defineOption("autoCloseBrackets", !1, function (b, c, d) {
+        d && d != a.Init && (b.removeKeyMap(f), b.state.closeBrackets = null), c && (b.state.closeBrackets = c, b.addKeyMap(f))
+    });
+    for (var e = b.pairs + "`", f = {
+            Backspace: j,
+            Enter: k
+        }, g = 0; g < e.length; g++) f["'" + e.charAt(g) + "'"] = h(e.charAt(g))
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror"), require("../fold/xml-fold")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror", "../fold/xml-fold"], a) : a(CodeMirror)
+}(function (a) {
+    function d(d) {
+        if (d.getOption("disableInput")) return a.Pass;
+        for (var e = d.listSelections(), f = [], i = 0; i < e.length; i++) {
+            if (!e[i].empty()) return a.Pass;
+            var j = e[i].head,
+                k = d.getTokenAt(j),
+                l = a.innerMode(d.getMode(), k.state),
+                m = l.state;
+            if ("xml" != l.mode.name || !m.tagName) return a.Pass;
+            var n = d.getOption("autoCloseTags"),
+                o = "html" == l.mode.configuration,
+                p = "object" == typeof n && n.dontCloseTags || o && b,
+                q = "object" == typeof n && n.indentTags || o && c,
+                r = m.tagName;
+            k.end > j.ch && (r = r.slice(0, r.length - k.end + j.ch));
+            var s = r.toLowerCase();
+            if (!r || "string" == k.type && (k.end != j.ch || !/[\"\']/.test(k.string.charAt(k.string.length - 1)) || 1 == k.string.length) || "tag" == k.type && "closeTag" == m.type || k.string.indexOf("/") == k.string.length - 1 || p && g(p, s) > -1 || h(d, r, j, m, !0)) return a.Pass;
+            var t = q && g(q, s) > -1;
+            f[i] = {
+                indent: t,
+                text: ">" + (t ? "\n\n" : "") + "</" + r + ">",
+                newPos: t ? a.Pos(j.line + 1, 0) : a.Pos(j.line, j.ch + 1)
+            }
+        }
+        for (var i = e.length - 1; i >= 0; i--) {
+            var u = f[i];
+            d.replaceRange(u.text, e[i].head, e[i].anchor, "+insert");
+            var v = d.listSelections()
+                .slice(0);
+            v[i] = {
+                head: u.newPos,
+                anchor: u.newPos
+            }, d.setSelections(v), u.indent && (d.indentLine(u.newPos.line, null, !0), d.indentLine(u.newPos.line + 1, null, !0))
+        }
+    }
+
+    function e(b, c) {
+        for (var d = b.listSelections(), e = [], f = c ? "/" : "</", g = 0; g < d.length; g++) {
+            if (!d[g].empty()) return a.Pass;
+            var i = d[g].head,
+                j = b.getTokenAt(i),
+                k = a.innerMode(b.getMode(), j.state),
+                l = k.state;
+            if (c && ("string" == j.type || "<" != j.string.charAt(0) || j.start != i.ch - 1)) return a.Pass;
+            var m;
+            if ("xml" != k.mode.name)
+                if ("htmlmixed" == b.getMode()
+                    .name && "javascript" == k.mode.name) m = f + "script";
+                else {
+                    if ("htmlmixed" != b.getMode()
+                        .name || "css" != k.mode.name) return a.Pass;
+                    m = f + "style"
+                } else {
+                if (!l.context || !l.context.tagName || h(b, l.context.tagName, i, l)) return a.Pass;
+                m = f + l.context.tagName;
+            }
+            ">" != b.getLine(i.line)
+                .charAt(j.end) && (m += ">"), e[g] = m
+        }
+        b.replaceSelections(e), d = b.listSelections();
+        for (var g = 0; g < d.length; g++)(g == d.length - 1 || d[g].head.line < d[g + 1].head.line) && b.indentLine(d[g].head.line)
+    }
+
+    function f(b) {
+        return b.getOption("disableInput") ? a.Pass : e(b, !0)
+    }
+
+    function g(a, b) {
+        if (a.indexOf) return a.indexOf(b);
+        for (var c = 0, d = a.length; d > c; ++c)
+            if (a[c] == b) return c;
+        return -1
+    }
+
+    function h(b, c, d, e, f) {
+        if (!a.scanForClosingTag) return !1;
+        var g = Math.min(b.lastLine() + 1, d.line + 500),
+            h = a.scanForClosingTag(b, d, null, g);
+        if (!h || h.tag != c) return !1;
+        for (var i = e.context, j = f ? 1 : 0; i && i.tagName == c; i = i.prev) ++j;
+        d = h.to;
+        for (var k = 1; j > k; k++) {
+            var l = a.scanForClosingTag(b, d, null, g);
+            if (!l || l.tag != c) return !1;
+            d = l.to
+        }
+        return !0
+    }
+    a.defineOption("autoCloseTags", !1, function (b, c, e) {
+        if (e != a.Init && e && b.removeKeyMap("autoCloseTags"), c) {
+            var g = {
+                name: "autoCloseTags"
+            };
+            ("object" != typeof c || c.whenClosing) && (g["'/'"] = function (a) {
+                return f(a)
+            }), ("object" != typeof c || c.whenOpening) && (g["'>'"] = function (a) {
+                return d(a)
+            }), b.addKeyMap(g)
+        }
+    });
+    var b = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"],
+        c = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4", "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"];
+    a.commands.closeTag = function (a) {
+        return e(a)
+    }
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+
+    function b(b, d, f, g) {
+        function j(a) {
+            var c = h(b, d);
+            if (!c || c.to.line - c.from.line < i) return null;
+            for (var e = b.findMarksAt(c.from), f = 0; f < e.length; ++f)
+                if (e[f].__isFold && "fold" !== g) {
+                    if (!a) return null;
+                    c.cleared = !0, e[f].clear()
+                }
+            return c
+        }
+        if (f && f.call) {
+            var h = f;
+            f = null
+        } else var h = e(b, f, "rangeFinder");
+        "number" == typeof d && (d = a.Pos(d, 0));
+        var i = e(b, f, "minFoldSize"),
+            k = j(!0);
+        if (e(b, f, "scanUp"))
+            for (; !k && d.line > b.firstLine();) d = a.Pos(d.line - 1, 0), k = j(!1);
+        if (k && !k.cleared && "unfold" !== g) {
+            var l = c(b, f);
+            a.on(l, "mousedown", function (b) {
+                m.clear(), a.e_preventDefault(b)
+            });
+            var m = b.markText(k.from, k.to, {
+                replacedWith: l,
+                clearOnEnter: !0,
+                __isFold: !0
+            });
+            m.on("clear", function (c, d) {
+                a.signal(b, "unfold", b, c, d)
+            }), a.signal(b, "fold", b, k.from, k.to)
+        }
+    }
+
+    function c(a, b) {
+        var c = e(a, b, "widget");
+        if ("string" == typeof c) {
+            var d = document.createTextNode(c);
+            c = document.createElement("span"), c.appendChild(d), c.className = "CodeMirror-foldmarker"
+        }
+        return c
+    }
+
+    function e(a, b, c) {
+        if (b && void 0 !== b[c]) return b[c];
+        var e = a.options.foldOptions;
+        return e && void 0 !== e[c] ? e[c] : d[c]
+    }
+    a.newFoldFunction = function (a, c) {
+        return function (d, e) {
+            b(d, e, {
+                rangeFinder: a,
+                widget: c
+            })
+        }
+    }, a.defineExtension("foldCode", function (a, c, d) {
+        b(this, a, c, d)
+    }), a.defineExtension("isFolded", function (a) {
+        for (var b = this.findMarksAt(a), c = 0; c < b.length; ++c)
+            if (b[c].__isFold) return !0
+    }), a.commands.toggleFold = function (a) {
+        a.foldCode(a.getCursor())
+    }, a.commands.fold = function (a) {
+        a.foldCode(a.getCursor(), null, "fold")
+    }, a.commands.unfold = function (a) {
+        a.foldCode(a.getCursor(), null, "unfold")
+    }, a.commands.foldAll = function (b) {
+        b.operation(function () {
+            for (var c = b.firstLine(), d = b.lastLine(); d >= c; c++) b.foldCode(a.Pos(c, 0), null, "fold")
+        })
+    }, a.commands.unfoldAll = function (b) {
+        b.operation(function () {
+            for (var c = b.firstLine(), d = b.lastLine(); d >= c; c++) b.foldCode(a.Pos(c, 0), null, "unfold")
+        })
+    }, a.registerHelper("fold", "combine", function () {
+        var a = Array.prototype.slice.call(arguments, 0);
+        return function (b, c) {
+            for (var d = 0; d < a.length; ++d) {
+                var e = a[d](b, c);
+                if (e) return e
+            }
+        }
+    }), a.registerHelper("fold", "auto", function (a, b) {
+        for (var c = a.getHelpers(b, "fold"), d = 0; d < c.length; d++) {
+            var e = c[d](a, b);
+            if (e) return e
+        }
+    });
+    var d = {
+        rangeFinder: a.fold.auto,
+        widget: "\u2194",
+        minFoldSize: 0,
+        scanUp: !1
+    };
+    a.defineOption("foldOptions", null), a.defineExtension("foldOption", function (a, b) {
+        return e(this, a, b)
+    })
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror"), require("./foldcode")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror", "./foldcode"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+
+    function c(a) {
+        this.options = a, this.from = this.to = 0
+    }
+
+    function d(a) {
+        return a === !0 && (a = {}), null == a.gutter && (a.gutter = "CodeMirror-foldgutter"), null == a.indicatorOpen && (a.indicatorOpen = "CodeMirror-foldgutter-open"), null == a.indicatorFolded && (a.indicatorFolded = "CodeMirror-foldgutter-folded"), a
+    }
+
+    function e(a, c) {
+        for (var d = a.findMarksAt(b(c)), e = 0; e < d.length; ++e)
+            if (d[e].__isFold && d[e].find()
+                .from.line == c) return d[e]
+    }
+
+    function f(a) {
+        if ("string" == typeof a) {
+            var b = document.createElement("div");
+            return b.className = a + " CodeMirror-guttermarker-subtle", b
+        }
+        return a.cloneNode(!0)
+    }
+
+    function g(a, c, d) {
+        var g = a.state.foldGutter.options,
+            h = c,
+            i = a.foldOption(g, "minFoldSize"),
+            j = a.foldOption(g, "rangeFinder");
+        a.eachLine(c, d, function (c) {
+            var d = null;
+            if (e(a, h)) d = f(g.indicatorFolded);
+            else {
+                var k = b(h, 0),
+                    l = j && j(a, k);
+                l && l.to.line - l.from.line >= i && (d = f(g.indicatorOpen))
+            }
+            a.setGutterMarker(c, g.gutter, d), ++h
+        })
+    }
+
+    function h(a) {
+        var b = a.getViewport(),
+            c = a.state.foldGutter;
+        c && (a.operation(function () {
+            g(a, b.from, b.to)
+        }), c.from = b.from, c.to = b.to)
+    }
+
+    function i(a, c, d) {
+        var f = a.state.foldGutter;
+        if (f) {
+            var g = f.options;
+            if (d == g.gutter) {
+                var h = e(a, c);
+                h ? h.clear() : a.foldCode(b(c, 0), g.rangeFinder)
+            }
+        }
+    }
+
+    function j(a) {
+        var b = a.state.foldGutter;
+        if (b) {
+            var c = b.options;
+            b.from = b.to = 0, clearTimeout(b.changeUpdate), b.changeUpdate = setTimeout(function () {
+                h(a)
+            }, c.foldOnChangeTimeSpan || 600)
+        }
+    }
+
+    function k(a) {
+        var b = a.state.foldGutter;
+        if (b) {
+            var c = b.options;
+            clearTimeout(b.changeUpdate), b.changeUpdate = setTimeout(function () {
+                var c = a.getViewport();
+                b.from == b.to || c.from - b.to > 20 || b.from - c.to > 20 ? h(a) : a.operation(function () {
+                    c.from < b.from && (g(a, c.from, b.from), b.from = c.from), c.to > b.to && (g(a, b.to, c.to), b.to = c.to)
+                })
+            }, c.updateViewportTimeSpan || 400)
+        }
+    }
+
+    function l(a, b) {
+        var c = a.state.foldGutter;
+        if (c) {
+            var d = b.line;
+            d >= c.from && d < c.to && g(a, d, d + 1)
+        }
+    }
+    a.defineOption("foldGutter", !1, function (b, e, f) {
+        f && f != a.Init && (b.clearGutter(b.state.foldGutter.options.gutter), b.state.foldGutter = null, b.off("gutterClick", i), b.off("change", j), b.off("viewportChange", k), b.off("fold", l), b.off("unfold", l), b.off("swapDoc", h)), e && (b.state.foldGutter = new c(d(e)), h(b), b.on("gutterClick", i), b.on("change", j), b.on("viewportChange", k), b.on("fold", l), b.on("unfold", l), b.on("swapDoc", h))
+    });
+    var b = a.Pos
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+    a.registerHelper("fold", "indent", function (b, c) {
+        var d = b.getOption("tabSize"),
+            e = b.getLine(c.line);
+        if (/\S/.test(e)) {
+            for (var f = function (b) {
+                    return a.countColumn(b, null, d)
+                }, g = f(e), h = null, i = c.line + 1, j = b.lastLine(); j >= i; ++i) {
+                var k = b.getLine(i),
+                    l = f(k);
+                if (l > g) h = i;
+                else if (/\S/.test(k)) break
+            }
+            return h ? {
+                from: a.Pos(c.line, e.length),
+                to: a.Pos(h, b.getLine(h)
+                    .length)
+            } : void 0
+        }
+    })
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+
+    function f(a) {
+        "object" == typeof a && (this.minChars = a.minChars, this.style = a.style, this.showToken = a.showToken, this.delay = a.delay, this.wordsOnly = a.wordsOnly), null == this.style && (this.style = c), null == this.minChars && (this.minChars = b), null == this.delay && (this.delay = d), null == this.wordsOnly && (this.wordsOnly = e), this.overlay = this.timeout = null
+    }
+
+    function g(a) {
+        var b = a.state.matchHighlighter;
+        clearTimeout(b.timeout), b.timeout = setTimeout(function () {
+            h(a)
+        }, b.delay)
+    }
+
+    function h(a) {
+        a.operation(function () {
+            var b = a.state.matchHighlighter;
+            if (b.overlay && (a.removeOverlay(b.overlay), b.overlay = null), !a.somethingSelected() && b.showToken) {
+                for (var c = b.showToken === !0 ? /[\w$]/ : b.showToken, d = a.getCursor(), e = a.getLine(d.line), f = d.ch, g = f; f && c.test(e.charAt(f - 1));) --f;
+                for (; g < e.length && c.test(e.charAt(g));) ++g;
+                return void(g > f && a.addOverlay(b.overlay = k(e.slice(f, g), c, b.style)))
+            }
+            var h = a.getCursor("from"),
+                j = a.getCursor("to");
+            if (h.line == j.line && (!b.wordsOnly || i(a, h, j))) {
+                var l = a.getRange(h, j)
+                    .replace(/^\s+|\s+$/g, "");
+                l.length >= b.minChars && a.addOverlay(b.overlay = k(l, !1, b.style))
+            }
+        })
+    }
+
+    function i(a, b, c) {
+        var d = a.getRange(b, c);
+        if (null !== d.match(/^\w+$/)) {
+            if (b.ch > 0) {
+                var e = {
+                        line: b.line,
+                        ch: b.ch - 1
+                    },
+                    f = a.getRange(e, b);
+                if (null === f.match(/\W/)) return !1
+            }
+            if (c.ch < a.getLine(b.line)
+                .length) {
+                var e = {
+                        line: c.line,
+                        ch: c.ch + 1
+                    },
+                    f = a.getRange(c, e);
+                if (null === f.match(/\W/)) return !1
+            }
+            return !0
+        }
+        return !1
+    }
+
+    function j(a, b) {
+        return !(a.start && b.test(a.string.charAt(a.start - 1)) || a.pos != a.string.length && b.test(a.string.charAt(a.pos)))
+    }
+
+    function k(a, b, c) {
+        return {
+            token: function (d) {
+                return !d.match(a) || b && !j(d, b) ? (d.next(), void(d.skipTo(a.charAt(0)) || d.skipToEnd())) : c
+            }
+        }
+    }
+    var b = 2,
+        c = "matchhighlight",
+        d = 100,
+        e = !1;
+    a.defineOption("highlightSelectionMatches", !1, function (b, c, d) {
+        if (d && d != a.Init) {
+            var e = b.state.matchHighlighter.overlay;
+            e && b.removeOverlay(e), clearTimeout(b.state.matchHighlighter.timeout), b.state.matchHighlighter = null, b.off("cursorActivity", g)
+        }
+        c && (b.state.matchHighlighter = new f(c), h(b), b.on("cursorActivity", g))
+    })
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    function e(a, b, e, g) {
+        var h = a.getLineHandle(b.line),
+            i = b.ch - 1,
+            j = i >= 0 && d[h.text.charAt(i)] || d[h.text.charAt(++i)];
+        if (!j) return null;
+        var k = ">" == j.charAt(1) ? 1 : -1;
+        if (e && k > 0 != (i == b.ch)) return null;
+        var l = a.getTokenTypeAt(c(b.line, i + 1)),
+            m = f(a, c(b.line, i + (k > 0 ? 1 : 0)), k, l || null, g);
+        return null == m ? null : {
+            from: c(b.line, i),
+            to: m && m.pos,
+            match: m && m.ch == j.charAt(0),
+            forward: k > 0
+        }
+    }
+
+    function f(a, b, e, f, g) {
+        for (var h = g && g.maxScanLineLength || 1e4, i = g && g.maxScanLines || 1e3, j = [], k = g && g.bracketRegex ? g.bracketRegex : /[(){}[\]]/, l = e > 0 ? Math.min(b.line + i, a.lastLine() + 1) : Math.max(a.firstLine() - 1, b.line - i), m = b.line; m != l; m += e) {
+            var n = a.getLine(m);
+            if (n) {
+                var o = e > 0 ? 0 : n.length - 1,
+                    p = e > 0 ? n.length : -1;
+                if (!(n.length > h))
+                    for (m == b.line && (o = b.ch - (0 > e ? 1 : 0)); o != p; o += e) {
+                        var q = n.charAt(o);
+                        if (k.test(q) && (void 0 === f || a.getTokenTypeAt(c(m, o + 1)) == f)) {
+                            var r = d[q];
+                            if (">" == r.charAt(1) == e > 0) j.push(q);
+                            else {
+                                if (!j.length) return {
+                                    pos: c(m, o),
+                                    ch: q
+                                };
+                                j.pop()
+                            }
+                        }
+                    }
+            }
+        }
+        return m - e == (e > 0 ? a.lastLine() : a.firstLine()) ? !1 : null
+    }
+
+    function g(a, d, f) {
+        for (var g = a.state.matchBrackets.maxHighlightLineLength || 1e3, h = [], i = a.listSelections(), j = 0; j < i.length; j++) {
+            var k = i[j].empty() && e(a, i[j].head, !1, f);
+            if (k && a.getLine(k.from.line)
+                .length <= g) {
+                var l = k.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
+                h.push(a.markText(k.from, c(k.from.line, k.from.ch + 1), {
+                        className: l
+                    })), k.to && a.getLine(k.to.line)
+                    .length <= g && h.push(a.markText(k.to, c(k.to.line, k.to.ch + 1), {
+                        className: l
+                    }))
+            }
+        }
+        if (h.length) {
+            b && a.state.focused && a.focus();
+            var m = function () {
+                a.operation(function () {
+                    for (var a = 0; a < h.length; a++) h[a].clear()
+                })
+            };
+            if (!d) return m;
+            setTimeout(m, 800)
+        }
+    }
+
+    function i(a) {
+        a.operation(function () {
+            h && (h(), h = null), h = g(a, !1, a.state.matchBrackets)
+        })
+    }
+    var b = /MSIE \d/.test(navigator.userAgent) && (null == document.documentMode || document.documentMode < 8),
+        c = a.Pos,
+        d = {
+            "(": ")>",
+            ")": "(<",
+            "[": "]>",
+            "]": "[<",
+            "{": "}>",
+            "}": "{<"
+        },
+        h = null;
+    a.defineOption("matchBrackets", !1, function (b, c, d) {
+        d && d != a.Init && b.off("cursorActivity", i), c && (b.state.matchBrackets = "object" == typeof c ? c : {}, b.on("cursorActivity", i))
+    }), a.defineExtension("matchBrackets", function () {
+        g(this, !0)
+    }), a.defineExtension("findMatchingBracket", function (a, b, c) {
+        return e(this, a, b, c)
+    }), a.defineExtension("scanForBracket", function (a, b, c, d) {
+        return f(this, a, b, c, d)
+    })
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror"), require("../fold/xml-fold")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror", "../fold/xml-fold"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+
+    function b(a) {
+        a.state.tagHit && a.state.tagHit.clear(), a.state.tagOther && a.state.tagOther.clear(), a.state.tagHit = a.state.tagOther = null
+    }
+
+    function c(c) {
+        c.state.failedTagMatch = !1, c.operation(function () {
+            if (b(c), !c.somethingSelected()) {
+                var d = c.getCursor(),
+                    e = c.getViewport();
+                e.from = Math.min(e.from, d.line), e.to = Math.max(d.line + 1, e.to);
+                var f = a.findMatchingTag(c, d, e);
+                if (f) {
+                    if (c.state.matchBothTags) {
+                        var g = "open" == f.at ? f.open : f.close;
+                        g && (c.state.tagHit = c.markText(g.from, g.to, {
+                            className: "CodeMirror-matchingtag"
+                        }))
+                    }
+                    var h = "close" == f.at ? f.open : f.close;
+                    h ? c.state.tagOther = c.markText(h.from, h.to, {
+                        className: "CodeMirror-matchingtag"
+                    }) : c.state.failedTagMatch = !0
+                }
+            }
+        })
+    }
+
+    function d(a) {
+        a.state.failedTagMatch && c(a)
+    }
+    a.defineOption("matchTags", !1, function (e, f, g) {
+        g && g != a.Init && (e.off("cursorActivity", c), e.off("viewportChange", d), b(e)), f && (e.state.matchBothTags = "object" == typeof f && f.bothTags, e.on("cursorActivity", c), e.on("viewportChange", d), c(e))
+    }), a.commands.toMatchingTag = function (b) {
+        var c = a.findMatchingTag(b, b.getCursor());
+        if (c) {
+            var d = "close" == c.at ? c.open : c.close;
+            d && b.extendSelection(d.to, d.from)
+        }
+    }
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+
+    function b(a, b) {
+        return "string" == typeof a ? a = new RegExp(a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), b ? "gi" : "g") : a.global || (a = new RegExp(a.source, a.ignoreCase ? "gi" : "g")), {
+            token: function (b) {
+                a.lastIndex = b.pos;
+                var c = a.exec(b.string);
+                return c && c.index == b.pos ? (b.pos += c[0].length, "searching") : void(c ? b.pos = c.index : b.skipToEnd())
+            }
+        }
+    }
+
+    function c() {
+        this.posFrom = this.posTo = this.lastQuery = this.query = null, this.overlay = null
+    }
+
+    function d(a) {
+        return a.state.search || (a.state.search = new c)
+    }
+
+    function e(a) {
+        return "string" == typeof a && a == a.toLowerCase()
+    }
+
+    function f(a, b, c) {
+        return a.getSearchCursor(b, c, e(b))
+    }
+
+    function g(a, b, c, d) {
+        a.openDialog(b, d, {
+            value: c,
+            selectValueOnOpen: !0,
+            closeOnEnter: !1,
+            onClose: function () {
+                p(a)
+            }
+        })
+    }
+
+    function h(a, b, c, d, e) {
+        a.openDialog ? a.openDialog(b, e, {
+            value: d,
+            selectValueOnOpen: !0
+        }) : e(prompt(c, d))
+    }
+
+    function i(a, b, c, d) {
+        a.openConfirm ? a.openConfirm(b, d) : confirm(c) && d[0]()
+    }
+
+    function j(a) {
+        return a.replace(/\\(.)/g, function (a, b) {
+            return "n" == b ? "\n" : "r" == b ? "\r" : b
+        })
+    }
+
+    function k(a) {
+        var b = a.match(/^\/(.*)\/([a-z]*)$/);
+        if (b) try {
+            a = new RegExp(b[1], -1 == b[2].indexOf("i") ? "" : "i")
+        } catch (c) {} else a = j(a);
+        return ("string" == typeof a ? "" == a : a.test("")) && (a = /x^/), a
+    }
+
+    function m(a, c, d) {
+        c.queryText = d, c.query = k(d), a.removeOverlay(c.overlay, e(c.query)), c.overlay = b(c.query, e(c.query)), a.addOverlay(c.overlay), a.showMatchesOnScrollbar && (c.annotate && (c.annotate.clear(), c.annotate = null), c.annotate = a.showMatchesOnScrollbar(c.query, e(c.query)))
+    }
+
+    function n(b, c, e) {
+        var f = d(b);
+        if (f.query) return o(b, c);
+        var i = b.getSelection() || f.lastQuery;
+        e && b.openDialog ? g(b, l, i, function (c, d) {
+            a.e_stop(d), c && (c != f.queryText && m(b, f, c), o(b, d.shiftKey))
+        }) : h(b, l, "Search for:", i, function (a) {
+            a && !f.query && b.operation(function () {
+                m(b, f, a), f.posFrom = f.posTo = b.getCursor(), o(b, c)
+            })
+        })
+    }
+
+    function o(b, c) {
+        b.operation(function () {
+            var e = d(b),
+                g = f(b, e.query, c ? e.posFrom : e.posTo);
+            (g.find(c) || (g = f(b, e.query, c ? a.Pos(b.lastLine()) : a.Pos(b.firstLine(), 0)), g.find(c))) && (b.setSelection(g.from(), g.to()), b.scrollIntoView({
+                from: g.from(),
+                to: g.to()
+            }, 20), e.posFrom = g.from(), e.posTo = g.to())
+        })
+    }
+
+    function p(a) {
+        a.operation(function () {
+            var b = d(a);
+            b.lastQuery = b.query, b.query && (b.query = b.queryText = null, a.removeOverlay(b.overlay), b.annotate && (b.annotate.clear(), b.annotate = null))
+        })
+    }
+
+    function t(a, b) {
+        if (!a.getOption("readOnly")) {
+            var c = a.getSelection() || d(a)
+                .lastQuery;
+            h(a, q, "Replace:", c, function (c) {
+                c && (c = k(c), h(a, r, "Replace with:", "", function (d) {
+                    if (d = j(d), b) a.operation(function () {
+                        for (var b = f(a, c); b.findNext();)
+                            if ("string" != typeof c) {
+                                var e = a.getRange(b.from(), b.to())
+                                    .match(c);
+                                b.replace(d.replace(/\$(\d)/g, function (a, b) {
+                                    return e[b]
+                                }))
+                            } else b.replace(d)
+                    });
+                    else {
+                        p(a);
+                        var e = f(a, c, a.getCursor()),
+                            g = function () {
+                                var d, b = e.from();
+                                !(d = e.findNext()) && (e = f(a, c), !(d = e.findNext()) || b && e.from()
+                                    .line == b.line && e.from()
+                                    .ch == b.ch) || (a.setSelection(e.from(), e.to()), a.scrollIntoView({
+                                    from: e.from(),
+                                    to: e.to()
+                                }), i(a, s, "Replace?", [function () {
+                                    h(d)
+                                }, g]))
+                            },
+                            h = function (a) {
+                                e.replace("string" == typeof c ? d : d.replace(/\$(\d)/g, function (b, c) {
+                                    return a[c]
+                                })), g()
+                            };
+                        g()
+                    }
+                }))
+            })
+        }
+    }
+    var l = 'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>',
+        q = 'Replace: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>',
+        r = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>',
+        s = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
+    a.commands.find = function (a) {
+        p(a), n(a)
+    }, a.commands.findPersistent = function (a) {
+        p(a), n(a, !1, !0)
+    }, a.commands.findNext = n, a.commands.findPrev = function (a) {
+        n(a, !0)
+    }, a.commands.clearSearch = p, a.commands.replace = t, a.commands.replaceAll = function (a) {
+        t(a, !0)
+    }
+}),
+function (a) {
+    "object" == typeof exports && "object" == typeof module ? a(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], a) : a(CodeMirror)
+}(function (a) {
+    "use strict";
+
+    function c(a, b) {
+        return a.line - b.line || a.ch - b.ch
+    }
+
+    function g(a, b, c, d) {
+        this.line = b, this.ch = c, this.cm = a, this.text = a.getLine(b), this.min = d ? d.from : a.firstLine(), this.max = d ? d.to - 1 : a.lastLine()
+    }
+
+    function h(a, c) {
+        var d = a.cm.getTokenTypeAt(b(a.line, c));
+        return d && /\btag\b/.test(d)
+    }
+
+    function i(a) {
+        return a.line >= a.max ? void 0 : (a.ch = 0, a.text = a.cm.getLine(++a.line), !0)
+    }
+
+    function j(a) {
+        return a.line <= a.min ? void 0 : (a.text = a.cm.getLine(--a.line), a.ch = a.text.length, !0)
+    }
+
+    function k(a) {
+        for (;;) {
+            var b = a.text.indexOf(">", a.ch);
+            if (-1 == b) {
+                if (i(a)) continue;
+                return
+            } {
+                if (h(a, b + 1)) {
+                    var c = a.text.lastIndexOf("/", b),
+                        d = c > -1 && !/\S/.test(a.text.slice(c + 1, b));
+                    return a.ch = b + 1, d ? "selfClose" : "regular"
+                }
+                a.ch = b + 1
+            }
+        }
+    }
+
+    function l(a) {
+        for (;;) {
+            var b = a.ch ? a.text.lastIndexOf("<", a.ch - 1) : -1;
+            if (-1 == b) {
+                if (j(a)) continue;
+                return
+            }
+            if (h(a, b + 1)) {
+                f.lastIndex = b, a.ch = b;
+                var c = f.exec(a.text);
+                if (c && c.index == b) return c
+            } else a.ch = b
+        }
+    }
+
+    function m(a) {
+        for (;;) {
+            f.lastIndex = a.ch;
+            var b = f.exec(a.text);
+            if (!b) {
+                if (i(a)) continue;
+                return
+            } {
+                if (h(a, b.index + 1)) return a.ch = b.index + b[0].length, b;
+                a.ch = b.index + 1
+            }
+        }
+    }
+
+    function n(a) {
+        for (;;) {
+            var b = a.ch ? a.text.lastIndexOf(">", a.ch - 1) : -1;
+            if (-1 == b) {
+                if (j(a)) continue;
+                return
+            } {
+                if (h(a, b + 1)) {
+                    var c = a.text.lastIndexOf("/", b),
+                        d = c > -1 && !/\S/.test(a.text.slice(c + 1, b));
+                    return a.ch = b + 1, d ? "selfClose" : "regular"
+                }
+                a.ch = b
+            }
+        }
+    }
+
+    function o(a, c) {
+        for (var d = [];;) {
+            var f, e = m(a),
+                g = a.line,
+                h = a.ch - (e ? e[0].length : 0);
+            if (!e || !(f = k(a))) return;
+            if ("selfClose" != f)
+                if (e[1]) {
+                    for (var i = d.length - 1; i >= 0; --i)
+                        if (d[i] == e[2]) {
+                            d.length = i;
+                            break
+                        }
+                    if (0 > i && (!c || c == e[2])) return {
+                        tag: e[2],
+                        from: b(g, h),
+                        to: b(a.line, a.ch)
+                    }
+                } else d.push(e[2])
+        }
+    }
+
+    function p(a, c) {
+        for (var d = [];;) {
+            var e = n(a);
+            if (!e) return;
+            if ("selfClose" != e) {
+                var f = a.line,
+                    g = a.ch,
+                    h = l(a);
+                if (!h) return;
+                if (h[1]) d.push(h[2]);
+                else {
+                    for (var i = d.length - 1; i >= 0; --i)
+                        if (d[i] == h[2]) {
+                            d.length = i;
+                            break
+                        }
+                    if (0 > i && (!c || c == h[2])) return {
+                        tag: h[2],
+                        from: b(a.line, a.ch),
+                        to: b(f, g)
+                    }
+                }
+            } else l(a)
+        }
+    }
+    var b = a.Pos,
+        d = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD",
+        e = d + "-:.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040",
+        f = new RegExp("<(/?)([" + d + "][" + e + "]*)", "g");
+    a.registerHelper("fold", "xml", function (a, c) {
+        for (var d = new g(a, c.line, 0);;) {
+            var f, e = m(d);
+            if (!e || d.line != c.line || !(f = k(d))) return;
+            if (!e[1] && "selfClose" != f) {
+                var c = b(d.line, d.ch),
+                    h = o(d, e[2]);
+                return h && {
+                    from: c,
+                    to: h.from
+                }
+            }
+        }
+    }), a.findMatchingTag = function (a, d, e) {
+        var f = new g(a, d.line, d.ch, e);
+        if (-1 != f.text.indexOf(">") || -1 != f.text.indexOf("<")) {
+            var h = k(f),
+                i = h && b(f.line, f.ch),
+                j = h && l(f);
+            if (h && j && !(c(f, d) > 0)) {
+                var m = {
+                    from: b(f.line, f.ch),
+                    to: i,
+                    tag: j[2]
+                };
+                return "selfClose" == h ? {
+                    open: m,
+                    close: null,
+                    at: "open"
+                } : j[1] ? {
+                    open: p(f, j[2]),
+                    close: m,
+                    at: "close"
+                } : (f = new g(a, i.line, i.ch, e), {
+                    open: m,
+                    close: o(f, j[2]),
+                    at: "open"
+                })
+            }
+        }
+    }, a.findEnclosingTag = function (a, b, c) {
+        for (var d = new g(a, b.line, b.ch, c);;) {
+            var e = p(d);
+            if (!e) break;
+            var f = new g(a, b.line, b.ch, c),
+                h = o(f, e.tag);
+            if (h) return {
+                open: e,
+                close: h
+            }
+        }
+    }, a.scanForClosingTag = function (a, b, c, d) {
+        var e = new g(a, b.line, b.ch, d ? {
+            from: 0,
+            to: d
+        } : null);
+        return o(e, c)
+    }
+});
diff --git a/htdocs/Libs/Codemirror/codemirror.min.js b/htdocs/Libs/Codemirror/codemirror.min.js
new file mode 100644
index 0000000..587863b
--- /dev/null
+++ b/htdocs/Libs/Codemirror/codemirror.min.js
@@ -0,0 +1,37 @@
+/* CodeMirror - Minified & Bundled
+   Generated on 2015. 08. 31. with http://codemirror.net/doc/compress.html
+   Version: HEAD
+
+   CodeMirror Library:
+   - codemirror.js
+   Modes:
+   - css.js
+   - htmlmixed.js
+   - javascript.js
+   - perl.js
+   - python.js
+   - shell.js
+   - xml.js
+   Add-ons:
+   - active-line.js
+   - brace-fold.js
+   - closebrackets.js
+   - closetag.js
+   - foldcode.js
+   - foldgutter.js
+   - indent-fold.js
+   - match-highlighter.js
+   - matchbrackets.js
+   - matchtags.js
+   - search.js
+   - xml-fold.js
+ */
+
+!function(a){if("object"==typeof exports&&"object"==typeof module)module.exports=a();else{if("function"==typeof define&&define.amd)return define([],a);this.CodeMirror=a()}}(function(){"use strict";function v(a,b){if(!(this instanceof v))return new v(a,b);this.options=b=b?hg(b):{},hg(Ad,b,!1),I(b);var c=b.value;"string"==typeof c&&(c=new af(c,b.mode,null,b.lineSeparator)),this.doc=c;var g=new v.inputStyles[b.inputStyle](this),h=this.display=new w(a,c,g);h.wrapper.CodeMirror=this,E(this),C(this),b.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),b.autofocus&&!n&&h.input.focus(),M(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:!1,cutIncoming:!1,selectingText:!1,draggingText:!1,highlight:new Yf,keySeq:null,specialChars:null};var i=this;d&&11>e&&setTimeout(function(){i.display.input.reset(!0)},20),pc(this),Bg(),Vb(this),this.curOp.forceUpdate=!0,ef(this,c),b.autofocus&&!n||i.hasFocus()?setTimeout(ig(Zc,this),20):$c(this);for(var j in Bd)Bd.hasOwnProperty(j)&&Bd[j](this,b[j],Dd);R(this),b.finishInit&&b.finishInit(this);for(var k=0;k<Hd.length;++k)Hd[k](this);Xb(this),f&&b.lineWrapping&&"optimizelegibility"==getComputedStyle(h.lineDiv).textRendering&&(h.lineDiv.style.textRendering="auto")}function w(b,c,g){var h=this;this.input=g,h.scrollbarFiller=pg("div",null,"CodeMirror-scrollbar-filler"),h.scrollbarFiller.setAttribute("cm-not-content","true"),h.gutterFiller=pg("div",null,"CodeMirror-gutter-filler"),h.gutterFiller.setAttribute("cm-not-content","true"),h.lineDiv=pg("div",null,"CodeMirror-code"),h.selectionDiv=pg("div",null,null,"position: relative; z-index: 1"),h.cursorDiv=pg("div",null,"CodeMirror-cursors"),h.measure=pg("div",null,"CodeMirror-measure"),h.lineMeasure=pg("div",null,"CodeMirror-measure"),h.lineSpace=pg("div",[h.measure,h.lineMeasure,h.selectionDiv,h.cursorDiv,h.lineDiv],null,"position: relative; outline: none"),h.mover=pg("div",[pg("div",[h.lineSpace],"CodeMirror-lines")],null,"position: relative"),h.sizer=pg("div",[h.mover],"CodeMirror-sizer"),h.sizerWidth=null,h.heightForcer=pg("div",null,null,"position: absolute; height: "+Tf+"px; width: 1px;"),h.gutters=pg("div",null,"CodeMirror-gutters"),h.lineGutter=null,h.scroller=pg("div",[h.sizer,h.heightForcer,h.gutters],"CodeMirror-scroll"),h.scroller.setAttribute("tabIndex","-1"),h.wrapper=pg("div",[h.scrollbarFiller,h.gutterFiller,h.scroller],"CodeMirror"),d&&8>e&&(h.gutters.style.zIndex=-1,h.scroller.style.paddingRight=0),f||a&&n||(h.scroller.draggable=!0),b&&(b.appendChild?b.appendChild(h.wrapper):b(h.wrapper)),h.viewFrom=h.viewTo=c.first,h.reportedViewFrom=h.reportedViewTo=c.first,h.view=[],h.renderedView=null,h.externalMeasured=null,h.viewOffset=0,h.lastWrapHeight=h.lastWrapWidth=0,h.updateLineNumbers=null,h.nativeBarWidth=h.barHeight=h.barWidth=0,h.scrollbarsClipped=!1,h.lineNumWidth=h.lineNumInnerWidth=h.lineNumChars=null,h.alignWidgets=!1,h.cachedCharWidth=h.cachedTextHeight=h.cachedPaddingH=null,h.maxLine=null,h.maxLineLength=0,h.maxLineChanged=!1,h.wheelDX=h.wheelDY=h.wheelStartX=h.wheelStartY=null,h.shift=!1,h.selForContextMenu=null,h.activeTouch=null,g.init(h)}function x(a){a.doc.mode=v.getMode(a.options,a.doc.modeOption),y(a)}function y(a){a.doc.iter(function(a){a.stateAfter&&(a.stateAfter=null),a.styles&&(a.styles=null)}),a.doc.frontier=a.doc.first,ib(a,100),a.state.modeGen++,a.curOp&&ic(a)}function z(a){a.options.lineWrapping?(xg(a.display.wrapper,"CodeMirror-wrap"),a.display.sizer.style.minWidth="",a.display.sizerWidth=null):(wg(a.display.wrapper,"CodeMirror-wrap"),H(a)),B(a),ic(a),Fb(a),setTimeout(function(){N(a)},100)}function A(a){var b=Rb(a.display),c=a.options.lineWrapping,d=c&&Math.max(5,a.display.scroller.clientWidth/Sb(a.display)-3);return function(e){if(we(a.doc,e))return 0;var f=0;if(e.widgets)for(var g=0;g<e.widgets.length;g++)e.widgets[g].height&&(f+=e.widgets[g].height);return c?f+(Math.ceil(e.text.length/d)||1)*b:f+b}}function B(a){var b=a.doc,c=A(a);b.iter(function(a){var b=c(a);b!=a.height&&jf(a,b)})}function C(a){a.display.wrapper.className=a.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+a.options.theme.replace(/(^|\s)\s*/g," cm-s-"),Fb(a)}function D(a){E(a),ic(a),setTimeout(function(){Q(a)},20)}function E(a){var b=a.display.gutters,c=a.options.gutters;rg(b);for(var d=0;d<c.length;++d){var e=c[d],f=b.appendChild(pg("div",null,"CodeMirror-gutter "+e));"CodeMirror-linenumbers"==e&&(a.display.lineGutter=f,f.style.width=(a.display.lineNumWidth||1)+"px")}b.style.display=d?"":"none",F(a)}function F(a){var b=a.display.gutters.offsetWidth;a.display.sizer.style.marginLeft=b+"px"}function G(a){if(0==a.height)return 0;for(var c,b=a.text.length,d=a;c=pe(d);){var e=c.find(0,!0);d=e.from.line,b+=e.from.ch-e.to.ch}for(d=a;c=qe(d);){var e=c.find(0,!0);b-=d.text.length-e.from.ch,d=e.to.line,b+=d.text.length-e.to.ch}return b}function H(a){var b=a.display,c=a.doc;b.maxLine=ff(c,c.first),b.maxLineLength=G(b.maxLine),b.maxLineChanged=!0,c.iter(function(a){var c=G(a);c>b.maxLineLength&&(b.maxLineLength=c,b.maxLine=a)})}function I(a){var b=dg(a.gutters,"CodeMirror-linenumbers");-1==b&&a.lineNumbers?a.gutters=a.gutters.concat(["CodeMirror-linenumbers"]):b>-1&&!a.lineNumbers&&(a.gutters=a.gutters.slice(0),a.gutters.splice(b,1))}function J(a){var b=a.display,c=b.gutters.offsetWidth,d=Math.round(a.doc.height+nb(a.display));return{clientHeight:b.scroller.clientHeight,viewHeight:b.wrapper.clientHeight,scrollWidth:b.scroller.scrollWidth,clientWidth:b.scroller.clientWidth,viewWidth:b.wrapper.clientWidth,barLeft:a.options.fixedGutter?c:0,docHeight:d,scrollHeight:d+pb(a)+b.barHeight,nativeBarWidth:b.nativeBarWidth,gutterWidth:c}}function K(a,b,c){this.cm=c;var f=this.vert=pg("div",[pg("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),g=this.horiz=pg("div",[pg("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");a(f),a(g),Jf(f,"scroll",function(){f.clientHeight&&b(f.scrollTop,"vertical")}),Jf(g,"scroll",function(){g.clientWidth&&b(g.scrollLeft,"horizontal")}),this.checkedOverlay=!1,d&&8>e&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")}function L(){}function M(a){a.display.scrollbars&&(a.display.scrollbars.clear(),a.display.scrollbars.addClass&&wg(a.display.wrapper,a.display.scrollbars.addClass)),a.display.scrollbars=new v.scrollbarModel[a.options.scrollbarStyle](function(b){a.display.wrapper.insertBefore(b,a.display.scrollbarFiller),Jf(b,"mousedown",function(){a.state.focused&&setTimeout(function(){a.display.input.focus()},0)}),b.setAttribute("cm-not-content","true")},function(b,c){"horizontal"==c?Ic(a,b):Hc(a,b)},a),a.display.scrollbars.addClass&&xg(a.display.wrapper,a.display.scrollbars.addClass)}function N(a,b){b||(b=J(a));var c=a.display.barWidth,d=a.display.barHeight;O(a,b);for(var e=0;4>e&&c!=a.display.barWidth||d!=a.display.barHeight;e++)c!=a.display.barWidth&&a.options.lineWrapping&&$(a),O(a,J(a)),c=a.display.barWidth,d=a.display.barHeight}function O(a,b){var c=a.display,d=c.scrollbars.update(b);c.sizer.style.paddingRight=(c.barWidth=d.right)+"px",c.sizer.style.paddingBottom=(c.barHeight=d.bottom)+"px",d.right&&d.bottom?(c.scrollbarFiller.style.display="block",c.scrollbarFiller.style.height=d.bottom+"px",c.scrollbarFiller.style.width=d.right+"px"):c.scrollbarFiller.style.display="",d.bottom&&a.options.coverGutterNextToScrollbar&&a.options.fixedGutter?(c.gutterFiller.style.display="block",c.gutterFiller.style.height=d.bottom+"px",c.gutterFiller.style.width=b.gutterWidth+"px"):c.gutterFiller.style.display=""}function P(a,b,c){var d=c&&null!=c.top?Math.max(0,c.top):a.scroller.scrollTop;d=Math.floor(d-mb(a));var e=c&&null!=c.bottom?c.bottom:d+a.wrapper.clientHeight,f=lf(b,d),g=lf(b,e);if(c&&c.ensure){var h=c.ensure.from.line,i=c.ensure.to.line;f>h?(f=h,g=lf(b,mf(ff(b,h))+a.wrapper.clientHeight)):Math.min(i,b.lastLine())>=g&&(f=lf(b,mf(ff(b,i))-a.wrapper.clientHeight),g=i)}return{from:f,to:Math.max(g,f+1)}}function Q(a){var b=a.display,c=b.view;if(b.alignWidgets||b.gutters.firstChild&&a.options.fixedGutter){for(var d=T(b)-b.scroller.scrollLeft+a.doc.scrollLeft,e=b.gutters.offsetWidth,f=d+"px",g=0;g<c.length;g++)if(!c[g].hidden){a.options.fixedGutter&&c[g].gutter&&(c[g].gutter.style.left=f);var h=c[g].alignable;if(h)for(var i=0;i<h.length;i++)h[i].style.left=f}a.options.fixedGutter&&(b.gutters.style.left=d+e+"px")}}function R(a){if(!a.options.lineNumbers)return!1;var b=a.doc,c=S(a.options,b.first+b.size-1),d=a.display;if(c.length!=d.lineNumChars){var e=d.measure.appendChild(pg("div",[pg("div",c)],"CodeMirror-linenumber CodeMirror-gutter-elt")),f=e.firstChild.offsetWidth,g=e.offsetWidth-f;return d.lineGutter.style.width="",d.lineNumInnerWidth=Math.max(f,d.lineGutter.offsetWidth-g)+1,d.lineNumWidth=d.lineNumInnerWidth+g,d.lineNumChars=d.lineNumInnerWidth?c.length:-1,d.lineGutter.style.width=d.lineNumWidth+"px",F(a),!0}return!1}function S(a,b){return String(a.lineNumberFormatter(b+a.firstLineNumber))}function T(a){return a.scroller.getBoundingClientRect().left-a.sizer.getBoundingClientRect().left}function U(a,b,c){var d=a.display;this.viewport=b,this.visible=P(d,a.doc,b),this.editorIsHidden=!d.wrapper.offsetWidth,this.wrapperHeight=d.wrapper.clientHeight,this.wrapperWidth=d.wrapper.clientWidth,this.oldDisplayWidth=qb(a),this.force=c,this.dims=aa(a),this.events=[]}function V(a){var b=a.display;!b.scrollbarsClipped&&b.scroller.offsetWidth&&(b.nativeBarWidth=b.scroller.offsetWidth-b.scroller.clientWidth,b.heightForcer.style.height=pb(a)+"px",b.sizer.style.marginBottom=-b.nativeBarWidth+"px",b.sizer.style.borderRightWidth=pb(a)+"px",b.scrollbarsClipped=!0)}function W(a,b){var c=a.display,d=a.doc;if(b.editorIsHidden)return kc(a),!1;if(!b.force&&b.visible.from>=c.viewFrom&&b.visible.to<=c.viewTo&&(null==c.updateLineNumbers||c.updateLineNumbers>=c.viewTo)&&c.renderedView==c.view&&0==oc(a))return!1;R(a)&&(kc(a),b.dims=aa(a));var e=d.first+d.size,f=Math.max(b.visible.from-a.options.viewportMargin,d.first),g=Math.min(e,b.visible.to+a.options.viewportMargin);c.viewFrom<f&&f-c.viewFrom<20&&(f=Math.max(d.first,c.viewFrom)),c.viewTo>g&&c.viewTo-g<20&&(g=Math.min(e,c.viewTo)),u&&(f=ue(a.doc,f),g=ve(a.doc,g));var h=f!=c.viewFrom||g!=c.viewTo||c.lastWrapHeight!=b.wrapperHeight||c.lastWrapWidth!=b.wrapperWidth;nc(a,f,g),c.viewOffset=mf(ff(a.doc,c.viewFrom)),a.display.mover.style.top=c.viewOffset+"px";var i=oc(a);if(!h&&0==i&&!b.force&&c.renderedView==c.view&&(null==c.updateLineNumbers||c.updateLineNumbers>=c.viewTo))return!1;var j=ug();return i>4&&(c.lineDiv.style.display="none"),ba(a,c.updateLineNumbers,b.dims),i>4&&(c.lineDiv.style.display=""),c.renderedView=c.view,j&&ug()!=j&&j.offsetHeight&&j.focus(),rg(c.cursorDiv),rg(c.selectionDiv),c.gutters.style.height=c.sizer.style.minHeight=0,h&&(c.lastWrapHeight=b.wrapperHeight,c.lastWrapWidth=b.wrapperWidth,ib(a,400)),c.updateLineNumbers=null,!0}function X(a,b){for(var c=b.viewport,d=!0;(d&&a.options.lineWrapping&&b.oldDisplayWidth!=qb(a)||(c&&null!=c.top&&(c={top:Math.min(a.doc.height+nb(a.display)-rb(a),c.top)}),b.visible=P(a.display,a.doc,c),!(b.visible.from>=a.display.viewFrom&&b.visible.to<=a.display.viewTo)))&&W(a,b);d=!1){$(a);var e=J(a);db(a),Z(a,e),N(a,e)}b.signal(a,"update",a),(a.display.viewFrom!=a.display.reportedViewFrom||a.display.viewTo!=a.display.reportedViewTo)&&(b.signal(a,"viewportChange",a,a.display.viewFrom,a.display.viewTo),a.display.reportedViewFrom=a.display.viewFrom,a.display.reportedViewTo=a.display.viewTo)}function Y(a,b){var c=new U(a,b);if(W(a,c)){$(a),X(a,c);var d=J(a);db(a),Z(a,d),N(a,d),c.finish()}}function Z(a,b){a.display.sizer.style.minHeight=b.docHeight+"px";var c=b.docHeight+a.display.barHeight;a.display.heightForcer.style.top=c+"px",a.display.gutters.style.height=Math.max(c+pb(a),b.clientHeight)+"px"}function $(a){for(var b=a.display,c=b.lineDiv.offsetTop,f=0;f<b.view.length;f++){var h,g=b.view[f];if(!g.hidden){if(d&&8>e){var i=g.node.offsetTop+g.node.offsetHeight;h=i-c,c=i}else{var j=g.node.getBoundingClientRect();h=j.bottom-j.top}var k=g.line.height-h;if(2>h&&(h=Rb(b)),(k>.001||-.001>k)&&(jf(g.line,h),_(g.line),g.rest))for(var l=0;l<g.rest.length;l++)_(g.rest[l])}}}function _(a){if(a.widgets)for(var b=0;b<a.widgets.length;++b)a.widgets[b].height=a.widgets[b].node.offsetHeight}function aa(a){for(var b=a.display,c={},d={},e=b.gutters.clientLeft,f=b.gutters.firstChild,g=0;f;f=f.nextSibling,++g)c[a.options.gutters[g]]=f.offsetLeft+f.clientLeft+e,d[a.options.gutters[g]]=f.clientWidth;return{fixedPos:T(b),gutterTotalWidth:b.gutters.offsetWidth,gutterLeft:c,gutterWidth:d,wrapperWidth:b.wrapper.clientWidth}}function ba(a,b,c){function i(b){var c=b.nextSibling;return f&&o&&a.display.currentWheelTarget==b?b.style.display="none":b.parentNode.removeChild(b),c}for(var d=a.display,e=a.options.lineNumbers,g=d.lineDiv,h=g.firstChild,j=d.view,k=d.viewFrom,l=0;l<j.length;l++){var m=j[l];if(m.hidden);else if(m.node&&m.node.parentNode==g){for(;h!=m.node;)h=i(h);var p=e&&null!=b&&k>=b&&m.lineNumber;m.changes&&(dg(m.changes,"gutter")>-1&&(p=!1),ca(a,m,k,c)),p&&(rg(m.lineNumber),m.lineNumber.appendChild(document.createTextNode(S(a.options,k)))),h=m.node.nextSibling}else{var n=ka(a,m,k,c);g.insertBefore(n,h)}k+=m.size}for(;h;)h=i(h)}function ca(a,b,c,d){for(var e=0;e<b.changes.length;e++){var f=b.changes[e];"text"==f?ga(a,b):"gutter"==f?ia(a,b,c,d):"class"==f?ha(b):"widget"==f&&ja(a,b,d)}b.changes=null}function da(a){return a.node==a.text&&(a.node=pg("div",null,null,"position: relative"),a.text.parentNode&&a.text.parentNode.replaceChild(a.node,a.text),a.node.appendChild(a.text),d&&8>e&&(a.node.style.zIndex=2)),a.node}function ea(a){var b=a.bgClass?a.bgClass+" "+(a.line.bgClass||""):a.line.bgClass;if(b&&(b+=" CodeMirror-linebackground"),a.background)b?a.background.className=b:(a.background.parentNode.removeChild(a.background),a.background=null);else if(b){var c=da(a);a.background=c.insertBefore(pg("div",null,b),c.firstChild)}}function fa(a,b){var c=a.display.externalMeasured;return c&&c.line==b.line?(a.display.externalMeasured=null,b.measure=c.measure,c.built):Qe(a,b)}function ga(a,b){var c=b.text.className,d=fa(a,b);b.text==b.node&&(b.node=d.pre),b.text.parentNode.replaceChild(d.pre,b.text),b.text=d.pre,d.bgClass!=b.bgClass||d.textClass!=b.textClass?(b.bgClass=d.bgClass,b.textClass=d.textClass,ha(b)):c&&(b.text.className=c)}function ha(a){ea(a),a.line.wrapClass?da(a).className=a.line.wrapClass:a.node!=a.text&&(a.node.className="");var b=a.textClass?a.textClass+" "+(a.line.textClass||""):a.line.textClass;a.text.className=b||""}function ia(a,b,c,d){if(b.gutter&&(b.node.removeChild(b.gutter),b.gutter=null),b.gutterBackground&&(b.node.removeChild(b.gutterBackground),b.gutterBackground=null),b.line.gutterClass){var e=da(b);b.gutterBackground=pg("div",null,"CodeMirror-gutter-background "+b.line.gutterClass,"left: "+(a.options.fixedGutter?d.fixedPos:-d.gutterTotalWidth)+"px; width: "+d.gutterTotalWidth+"px"),e.insertBefore(b.gutterBackground,b.text)}var f=b.line.gutterMarkers;if(a.options.lineNumbers||f){var e=da(b),g=b.gutter=pg("div",null,"CodeMirror-gutter-wrapper","left: "+(a.options.fixedGutter?d.fixedPos:-d.gutterTotalWidth)+"px");if(a.display.input.setUneditable(g),e.insertBefore(g,b.text),b.line.gutterClass&&(g.className+=" "+b.line.gutterClass),!a.options.lineNumbers||f&&f["CodeMirror-linenumbers"]||(b.lineNumber=g.appendChild(pg("div",S(a.options,c),"CodeMirror-linenumber CodeMirror-gutter-elt","left: "+d.gutterLeft["CodeMirror-linenumbers"]+"px; width: "+a.display.lineNumInnerWidth+"px"))),f)for(var h=0;h<a.options.gutters.length;++h){var i=a.options.gutters[h],j=f.hasOwnProperty(i)&&f[i];j&&g.appendChild(pg("div",[j],"CodeMirror-gutter-elt","left: "+d.gutterLeft[i]+"px; width: "+d.gutterWidth[i]+"px"))}}}function ja(a,b,c){b.alignable&&(b.alignable=null);for(var e,d=b.node.firstChild;d;d=e){var e=d.nextSibling;"CodeMirror-linewidget"==d.className&&b.node.removeChild(d)}la(a,b,c)}function ka(a,b,c,d){var e=fa(a,b);return b.text=b.node=e.pre,e.bgClass&&(b.bgClass=e.bgClass),e.textClass&&(b.textClass=e.textClass),ha(b),ia(a,b,c,d),la(a,b,d),b.node}function la(a,b,c){if(ma(a,b.line,b,c,!0),b.rest)for(var d=0;d<b.rest.length;d++)ma(a,b.rest[d],b,c,!1)}function ma(a,b,c,d,e){if(b.widgets)for(var f=da(c),g=0,h=b.widgets;g<h.length;++g){var i=h[g],j=pg("div",[i.node],"CodeMirror-linewidget");i.handleMouseEvents||j.setAttribute("cm-ignore-events","true"),na(i,j,c,d),a.display.input.setUneditable(j),e&&i.above?f.insertBefore(j,c.gutter||c.text):f.appendChild(j),Nf(i,"redraw")}}function na(a,b,c,d){if(a.noHScroll){(c.alignable||(c.alignable=[])).push(b);var e=d.wrapperWidth;b.style.left=d.fixedPos+"px",a.coverGutter||(e-=d.gutterTotalWidth,b.style.paddingLeft=d.gutterTotalWidth+"px"),b.style.width=e+"px"}a.coverGutter&&(b.style.zIndex=5,b.style.position="relative",a.noHScroll||(b.style.marginLeft=-d.gutterTotalWidth+"px"))}function qa(a){return oa(a.line,a.ch)}function ra(a,b){return pa(a,b)<0?b:a}function sa(a,b){return pa(a,b)<0?a:b}function ta(a){a.state.focused||(a.display.input.focus(),Zc(a))}function ua(a){return a.options.readOnly||a.doc.cantEdit}function wa(a,b,c,d,e){var f=a.doc;a.display.shift=!1,d||(d=f.sel);var g=a.state.pasteIncoming||"paste"==e,h=f.splitLines(b),i=null;if(g&&d.ranges.length>1)if(va&&va.join("\n")==b){if(d.ranges.length%va.length==0){i=[];for(var j=0;j<va.length;j++)i.push(f.splitLines(va[j]))}}else h.length==d.ranges.length&&(i=eg(h,function(a){return[a]}));for(var j=d.ranges.length-1;j>=0;j--){var k=d.ranges[j],l=k.from(),m=k.to();k.empty()&&(c&&c>0?l=oa(l.line,l.ch-c):a.state.overwrite&&!g&&(m=oa(m.line,Math.min(ff(f,m.line).text.length,m.ch+bg(h).length))));var n=a.curOp.updateInput,o={from:l,to:m,text:i?i[j%i.length]:h,origin:e||(g?"paste":a.state.cutIncoming?"cut":"+input")};hd(a.doc,o),Nf(a,"inputRead",a,o)}b&&!g&&ya(a,b),td(a),a.curOp.updateInput=n,a.curOp.typing=!0,a.state.pasteIncoming=a.state.cutIncoming=!1}function xa(a,b){var c=a.clipboardData&&a.clipboardData.getData("text/plain");return c?(a.preventDefault(),ua(b)||b.options.disableInput||cc(b,function(){wa(b,c,0,null,"paste")}),!0):void 0}function ya(a,b){if(a.options.electricChars&&a.options.smartIndent)for(var c=a.doc.sel,d=c.ranges.length-1;d>=0;d--){var e=c.ranges[d];if(!(e.head.ch>100||d&&c.ranges[d-1].head.line==e.head.line)){var f=a.getModeAt(e.head),g=!1;if(f.electricChars){for(var h=0;h<f.electricChars.length;h++)if(b.indexOf(f.electricChars.charAt(h))>-1){g=vd(a,e.head.line,"smart");break}}else f.electricInput&&f.electricInput.test(ff(a.doc,e.head.line).text.slice(0,e.head.ch))&&(g=vd(a,e.head.line,"smart"));g&&Nf(a,"electricInput",a,e.head.line)}}}function za(a){for(var b=[],c=[],d=0;d<a.doc.sel.ranges.length;d++){var e=a.doc.sel.ranges[d].head.line,f={anchor:oa(e,0),head:oa(e+1,0)};c.push(f),b.push(a.getRange(f.anchor,f.head))}return{text:b,ranges:c}}function Aa(a){a.setAttribute("autocorrect","off"),a.setAttribute("autocapitalize","off"),a.setAttribute("spellcheck","false")}function Ba(a){this.cm=a,this.prevInput="",this.pollingFast=!1,this.polling=new Yf,this.inaccurateSelection=!1,this.hasSelection=!1,this.composing=null}function Ca(){var a=pg("textarea",null,null,"position: absolute; padding: 0; width: 1px; height: 1em; outline: none"),b=pg("div",[a],null,"overflow: hidden; position: relative; width: 3px; height: 0px;");return f?a.style.width="1000px":a.setAttribute("wrap","off"),m&&(a.style.border="1px solid black"),Aa(a),b}function Da(a){this.cm=a,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new Yf,this.gracePeriod=!1}function Ea(a,b){var c=wb(a,b.line);if(!c||c.hidden)return null;var d=ff(a.doc,b.line),e=tb(c,d,b.line),f=nf(d),g="left";if(f){var h=Yg(f,b.ch);g=h%2?"right":"left"}var i=Ab(e.map,b.ch,g);return i.offset="right"==i.collapse?i.end:i.start,i}function Fa(a,b){return b&&(a.bad=!0),a}function Ga(a,b,c){var d;if(b==a.display.lineDiv){if(d=a.display.lineDiv.childNodes[c],!d)return Fa(a.clipPos(oa(a.display.viewTo-1)),!0);b=null,c=0}else for(d=b;;d=d.parentNode){if(!d||d==a.display.lineDiv)return null;if(d.parentNode&&d.parentNode==a.display.lineDiv)break}for(var e=0;e<a.display.view.length;e++){var f=a.display.view[e];if(f.node==d)return Ha(f,b,c)}}function Ha(a,b,c){function k(b,c,d){for(var e=-1;e<(j?j.length:0);e++)for(var f=0>e?i.map:j[e],g=0;g<f.length;g+=3){var h=f[g+2];if(h==b||h==c){var k=kf(0>e?a.line:a.rest[e]),l=f[g]+d;return(0>d||h!=b)&&(l=f[g+(d?1:0)]),oa(k,l)}}}var d=a.text.firstChild,e=!1;if(!b||!tg(d,b))return Fa(oa(kf(a.line),0),!0);if(b==d&&(e=!0,b=d.childNodes[c],c=0,!b)){var f=a.rest?bg(a.rest):a.line;return Fa(oa(kf(f),f.text.length),e)}var g=3==b.nodeType?b:null,h=b;for(g||1!=b.childNodes.length||3!=b.firstChild.nodeType||(g=b.firstChild,c&&(c=g.nodeValue.length));h.parentNode!=d;)h=h.parentNode;var i=a.measure,j=i.maps,l=k(g,h,c);if(l)return Fa(l,e);for(var m=h.nextSibling,n=g?g.nodeValue.length-c:0;m;m=m.nextSibling){if(l=k(m,m.firstChild,0))return Fa(oa(l.line,l.ch-n),e);n+=m.textContent.length}for(var o=h.previousSibling,n=c;o;o=o.previousSibling){if(l=k(o,o.firstChild,-1))return Fa(oa(l.line,l.ch+n),e);n+=m.textContent.length}}function Ia(a,b,c,d,e){function i(a){return function(b){return b.id==a}}function j(b){if(1==b.nodeType){var c=b.getAttribute("cm-text");if(null!=c)return""==c&&(c=b.textContent.replace(/\u200b/g,"")),void(f+=c);var l,k=b.getAttribute("cm-marker");if(k){var m=a.findMarks(oa(d,0),oa(e+1,0),i(+k));return void(m.length&&(l=m[0].find())&&(f+=gf(a.doc,l.from,l.to).join(h)))}if("false"==b.getAttribute("contenteditable"))return;for(var n=0;n<b.childNodes.length;n++)j(b.childNodes[n]);/^(pre|div|p)$/i.test(b.nodeName)&&(g=!0)}else if(3==b.nodeType){var o=b.nodeValue;if(!o)return;g&&(f+=h,g=!1),f+=o}}for(var f="",g=!1,h=a.doc.lineSeparator();j(b),b!=c;)b=b.nextSibling;return f}function Ja(a,b){this.ranges=a,this.primIndex=b}function Ka(a,b){this.anchor=a,this.head=b}function La(a,b){var c=a[b];a.sort(function(a,b){return pa(a.from(),b.from())}),b=dg(a,c);for(var d=1;d<a.length;d++){var e=a[d],f=a[d-1];if(pa(f.to(),e.from())>=0){var g=sa(f.from(),e.from()),h=ra(f.to(),e.to()),i=f.empty()?e.from()==e.head:f.from()==f.head;b>=d&&--b,a.splice(--d,2,new Ka(i?h:g,i?g:h))}}return new Ja(a,b)}function Ma(a,b){return new Ja([new Ka(a,b||a)],0)}function Na(a,b){return Math.max(a.first,Math.min(b,a.first+a.size-1))}function Oa(a,b){if(b.line<a.first)return oa(a.first,0);var c=a.first+a.size-1;return b.line>c?oa(c,ff(a,c).text.length):Pa(b,ff(a,b.line).text.length)}function Pa(a,b){var c=a.ch;return null==c||c>b?oa(a.line,b):0>c?oa(a.line,0):a}function Qa(a,b){return b>=a.first&&b<a.first+a.size}function Ra(a,b){for(var c=[],d=0;d<b.length;d++)c[d]=Oa(a,b[d]);return c}function Sa(a,b,c,d){if(a.cm&&a.cm.display.shift||a.extend){var e=b.anchor;if(d){var f=pa(c,e)<0;f!=pa(d,e)<0?(e=c,c=d):f!=pa(c,d)<0&&(c=d)}return new Ka(e,c)}return new Ka(d||c,c)}function Ta(a,b,c,d){Za(a,new Ja([Sa(a,a.sel.primary(),b,c)],0),d)}function Ua(a,b,c){for(var d=[],e=0;e<a.sel.ranges.length;e++)d[e]=Sa(a,a.sel.ranges[e],b[e],null);var f=La(d,a.sel.primIndex);Za(a,f,c)}function Va(a,b,c,d){var e=a.sel.ranges.slice(0);e[b]=c,Za(a,La(e,a.sel.primIndex),d)}function Wa(a,b,c,d){Za(a,Ma(b,c),d)}function Xa(a,b){var c={ranges:b.ranges,update:function(b){this.ranges=[];for(var c=0;c<b.length;c++)this.ranges[c]=new Ka(Oa(a,b[c].anchor),Oa(a,b[c].head))}};return Lf(a,"beforeSelectionChange",a,c),a.cm&&Lf(a.cm,"beforeSelectionChange",a.cm,c),c.ranges!=b.ranges?La(c.ranges,c.ranges.length-1):b}function Ya(a,b,c){var d=a.history.done,e=bg(d);e&&e.ranges?(d[d.length-1]=b,$a(a,b,c)):Za(a,b,c)}function Za(a,b,c){$a(a,b,c),uf(a,a.sel,a.cm?a.cm.curOp.id:NaN,c)}function $a(a,b,c){(Rf(a,"beforeSelectionChange")||a.cm&&Rf(a.cm,"beforeSelectionChange"))&&(b=Xa(a,b));var d=c&&c.bias||(pa(b.primary().head,a.sel.primary().head)<0?-1:1);_a(a,bb(a,b,d,!0)),c&&c.scroll===!1||!a.cm||td(a.cm)}function _a(a,b){b.equals(a.sel)||(a.sel=b,a.cm&&(a.cm.curOp.updateInput=a.cm.curOp.selectionChanged=!0,Qf(a.cm)),Nf(a,"cursorActivity",a))}function ab(a){_a(a,bb(a,a.sel,null,!1),Vf)}function bb(a,b,c,d){for(var e,f=0;f<b.ranges.length;f++){var g=b.ranges[f],h=cb(a,g.anchor,c,d),i=cb(a,g.head,c,d);(e||h!=g.anchor||i!=g.head)&&(e||(e=b.ranges.slice(0,f)),e[f]=new Ka(h,i))}return e?La(e,b.primIndex):b}function cb(a,b,c,d){var e=!1,f=b,g=c||1;a.cantEdit=!1;a:for(;;){var h=ff(a,f.line);if(h.markedSpans)for(var i=0;i<h.markedSpans.length;++i){var j=h.markedSpans[i],k=j.marker;if((null==j.from||(k.inclusiveLeft?j.from<=f.ch:j.from<f.ch))&&(null==j.to||(k.inclusiveRight?j.to>=f.ch:j.to>f.ch))){if(d&&(Lf(k,"beforeCursorEnter"),k.explicitlyCleared)){if(h.markedSpans){--i;continue}break}if(!k.atomic)continue;var l=k.find(0>g?-1:1);if(0==pa(l,f)&&(l.ch+=g,l.ch<0?l=l.line>a.first?Oa(a,oa(l.line-1)):null:l.ch>h.text.length&&(l=l.line<a.first+a.size-1?oa(l.line+1,0):null),!l)){if(e)return d?(a.cantEdit=!0,oa(a.first,0)):cb(a,b,c,!0);e=!0,l=b,g=-g}f=l;continue a}}return f}}function db(a){a.display.input.showSelection(a.display.input.prepareSelection())}function eb(a,b){for(var c=a.doc,d={},e=d.cursors=document.createDocumentFragment(),f=d.selection=document.createDocumentFragment(),g=0;g<c.sel.ranges.length;g++)if(b!==!1||g!=c.sel.primIndex){var h=c.sel.ranges[g],i=h.empty();(i||a.options.showCursorWhenSelecting)&&fb(a,h.head,e),i||gb(a,h,f)}return d}function fb(a,b,c){var d=Lb(a,b,"div",null,null,!a.options.singleCursorHeightPerLine),e=c.appendChild(pg("div","\xa0","CodeMirror-cursor"));if(e.style.left=d.left+"px",e.style.top=d.top+"px",e.style.height=Math.max(0,d.bottom-d.top)*a.options.cursorHeight+"px",d.other){var f=c.appendChild(pg("div","\xa0","CodeMirror-cursor CodeMirror-secondarycursor"));f.style.display="",f.style.left=d.other.left+"px",f.style.top=d.other.top+"px",f.style.height=.85*(d.other.bottom-d.other.top)+"px"}}function gb(a,b,c){function j(a,b,c,d){0>b&&(b=0),b=Math.round(b),d=Math.round(d),f.appendChild(pg("div",null,"CodeMirror-selected","position: absolute; left: "+a+"px; top: "+b+"px; width: "+(null==c?i-a:c)+"px; height: "+(d-b)+"px"))}function k(b,c,d){function m(c,d){return Kb(a,oa(b,c),"div",f,d)}var k,l,f=ff(e,b),g=f.text.length;return Og(nf(f),c||0,null==d?g:d,function(a,b,e){var n,o,p,f=m(a,"left");if(a==b)n=f,o=p=f.left;else{if(n=m(b-1,"right"),"rtl"==e){var q=f;f=n,n=q}o=f.left,p=n.right}null==c&&0==a&&(o=h),n.top-f.top>3&&(j(o,f.top,null,f.bottom),o=h,f.bottom<n.top&&j(o,f.bottom,null,n.top)),null==d&&b==g&&(p=i),(!k||f.top<k.top||f.top==k.top&&f.left<k.left)&&(k=f),(!l||n.bottom>l.bottom||n.bottom==l.bottom&&n.right>l.right)&&(l=n),h+1>o&&(o=h),j(o,n.top,p-o,n.bottom)}),{start:k,end:l}}var d=a.display,e=a.doc,f=document.createDocumentFragment(),g=ob(a.display),h=g.left,i=Math.max(d.sizerWidth,qb(a)-d.sizer.offsetLeft)-g.right,l=b.from(),m=b.to();if(l.line==m.line)k(l.line,l.ch,m.ch);else{var n=ff(e,l.line),o=ff(e,m.line),p=se(n)==se(o),q=k(l.line,l.ch,p?n.text.length+1:null).end,r=k(m.line,p?0:null,m.ch).start;p&&(q.top<r.top-2?(j(q.right,q.top,null,q.bottom),j(h,r.top,r.left,r.bottom)):j(q.right,q.top,r.left-q.right,q.bottom)),q.bottom<r.top&&j(h,q.bottom,null,r.top)}c.appendChild(f)}function hb(a){if(a.state.focused){var b=a.display;clearInterval(b.blinker);var c=!0;b.cursorDiv.style.visibility="",a.options.cursorBlinkRate>0?b.blinker=setInterval(function(){b.cursorDiv.style.visibility=(c=!c)?"":"hidden"},a.options.cursorBlinkRate):a.options.cursorBlinkRate<0&&(b.cursorDiv.style.visibility="hidden")}}function ib(a,b){a.doc.mode.startState&&a.doc.frontier<a.display.viewTo&&a.state.highlight.set(b,ig(jb,a))}function jb(a){var b=a.doc;if(b.frontier<b.first&&(b.frontier=b.first),!(b.frontier>=a.display.viewTo)){var c=+new Date+a.options.workTime,d=Jd(b.mode,lb(a,b.frontier)),e=[];b.iter(b.frontier,Math.min(b.first+b.size,a.display.viewTo+500),function(f){if(b.frontier>=a.display.viewFrom){var g=f.styles,h=f.text.length>a.options.maxHighlightLength,i=Ke(a,f,h?Jd(b.mode,d):d,!0);f.styles=i.styles;var j=f.styleClasses,k=i.classes;k?f.styleClasses=k:j&&(f.styleClasses=null);for(var l=!g||g.length!=f.styles.length||j!=k&&(!j||!k||j.bgClass!=k.bgClass||j.textClass!=k.textClass),m=0;!l&&m<g.length;++m)l=g[m]!=f.styles[m];l&&e.push(b.frontier),f.stateAfter=h?d:Jd(b.mode,d)}else f.text.length<=a.options.maxHighlightLength&&Me(a,f.text,d),f.stateAfter=b.frontier%5==0?Jd(b.mode,d):null;return++b.frontier,+new Date>c?(ib(a,a.options.workDelay),!0):void 0}),e.length&&cc(a,function(){for(var b=0;b<e.length;b++)jc(a,e[b],"text")})}}function kb(a,b,c){for(var d,e,f=a.doc,g=c?-1:b-(a.doc.mode.innerMode?1e3:100),h=b;h>g;--h){if(h<=f.first)return f.first;var i=ff(f,h-1);if(i.stateAfter&&(!c||h<=f.frontier))return h;var j=Zf(i.text,null,a.options.tabSize);(null==e||d>j)&&(e=h-1,d=j)}return e}function lb(a,b,c){var d=a.doc,e=a.display;if(!d.mode.startState)return!0;var f=kb(a,b,c),g=f>d.first&&ff(d,f-1).stateAfter;return g=g?Jd(d.mode,g):Kd(d.mode),d.iter(f,b,function(c){Me(a,c.text,g);var h=f==b-1||f%5==0||f>=e.viewFrom&&f<e.viewTo;c.stateAfter=h?Jd(d.mode,g):null,++f}),c&&(d.frontier=f),g}function mb(a){return a.lineSpace.offsetTop}function nb(a){return a.mover.offsetHeight-a.lineSpace.offsetHeight}function ob(a){if(a.cachedPaddingH)return a.cachedPaddingH;var b=sg(a.measure,pg("pre","x")),c=window.getComputedStyle?window.getComputedStyle(b):b.currentStyle,d={left:parseInt(c.paddingLeft),right:parseInt(c.paddingRight)};return isNaN(d.left)||isNaN(d.right)||(a.cachedPaddingH=d),d}function pb(a){return Tf-a.display.nativeBarWidth}function qb(a){return a.display.scroller.clientWidth-pb(a)-a.display.barWidth}function rb(a){return a.display.scroller.clientHeight-pb(a)-a.display.barHeight}function sb(a,b,c){var d=a.options.lineWrapping,e=d&&qb(a);if(!b.measure.heights||d&&b.measure.width!=e){var f=b.measure.heights=[];if(d){b.measure.width=e;for(var g=b.text.firstChild.getClientRects(),h=0;h<g.length-1;h++){var i=g[h],j=g[h+1];Math.abs(i.bottom-j.bottom)>2&&f.push((i.bottom+j.top)/2-c.top)}}f.push(c.bottom-c.top)}}function tb(a,b,c){if(a.line==b)return{map:a.measure.map,cache:a.measure.cache};for(var d=0;d<a.rest.length;d++)if(a.rest[d]==b)return{map:a.measure.maps[d],cache:a.measure.caches[d]};for(var d=0;d<a.rest.length;d++)if(kf(a.rest[d])>c)return{map:a.measure.maps[d],cache:a.measure.caches[d],before:!0}}function ub(a,b){b=se(b);var c=kf(b),d=a.display.externalMeasured=new gc(a.doc,b,c);d.lineN=c;var e=d.built=Qe(a,d);return d.text=e.pre,sg(a.display.lineMeasure,e.pre),d}function vb(a,b,c,d){return yb(a,xb(a,b),c,d)}function wb(a,b){if(b>=a.display.viewFrom&&b<a.display.viewTo)return a.display.view[lc(a,b)];var c=a.display.externalMeasured;return c&&b>=c.lineN&&b<c.lineN+c.size?c:void 0}function xb(a,b){var c=kf(b),d=wb(a,c);d&&!d.text?d=null:d&&d.changes&&(ca(a,d,c,aa(a)),a.curOp.forceUpdate=!0),d||(d=ub(a,b));var e=tb(d,b,c);return{line:b,view:d,rect:null,map:e.map,cache:e.cache,before:e.before,hasHeights:!1}}function yb(a,b,c,d,e){b.before&&(c=-1);var g,f=c+(d||"");return b.cache.hasOwnProperty(f)?g=b.cache[f]:(b.rect||(b.rect=b.view.text.getBoundingClientRect()),b.hasHeights||(sb(a,b.view,b.rect),b.hasHeights=!0),g=Bb(a,b,c,d),g.bogus||(b.cache[f]=g)),{left:g.left,right:g.right,top:e?g.rtop:g.top,bottom:e?g.rbottom:g.bottom}}function Ab(a,b,c){for(var d,e,f,g,h=0;h<a.length;h+=3){var i=a[h],j=a[h+1];if(i>b?(e=0,f=1,g="left"):j>b?(e=b-i,f=e+1):(h==a.length-3||b==j&&a[h+3]>b)&&(f=j-i,e=f-1,b>=j&&(g="right")),null!=e){if(d=a[h+2],i==j&&c==(d.insertLeft?"left":"right")&&(g=c),"left"==c&&0==e)for(;h&&a[h-2]==a[h-3]&&a[h-1].insertLeft;)d=a[(h-=3)+2],g="left";if("right"==c&&e==j-i)for(;h<a.length-3&&a[h+3]==a[h+4]&&!a[h+5].insertLeft;)d=a[(h+=3)+2],g="right";break}}return{node:d,start:e,end:f,collapse:g,coverStart:i,coverEnd:j}}function Bb(a,b,c,f){var l,g=Ab(b.map,c,f),h=g.node,i=g.start,j=g.end,k=g.collapse;if(3==h.nodeType){for(var m=0;4>m;m++){for(;i&&og(b.line.text.charAt(g.coverStart+i));)--i;for(;g.coverStart+j<g.coverEnd&&og(b.line.text.charAt(g.coverStart+j));)++j;
+if(d&&9>e&&0==i&&j==g.coverEnd-g.coverStart)l=h.parentNode.getBoundingClientRect();else if(d&&a.options.lineWrapping){var n=qg(h,i,j).getClientRects();l=n.length?n["right"==f?n.length-1:0]:zb}else l=qg(h,i,j).getBoundingClientRect()||zb;if(l.left||l.right||0==i)break;j=i,i-=1,k="right"}d&&11>e&&(l=Cb(a.display.measure,l))}else{i>0&&(k=f="right");var n;l=a.options.lineWrapping&&(n=h.getClientRects()).length>1?n["right"==f?n.length-1:0]:h.getBoundingClientRect()}if(d&&9>e&&!i&&(!l||!l.left&&!l.right)){var o=h.parentNode.getClientRects()[0];l=o?{left:o.left,right:o.left+Sb(a.display),top:o.top,bottom:o.bottom}:zb}for(var p=l.top-b.rect.top,q=l.bottom-b.rect.top,r=(p+q)/2,s=b.view.measure.heights,m=0;m<s.length-1&&!(r<s[m]);m++);var t=m?s[m-1]:0,u=s[m],v={left:("right"==k?l.right:l.left)-b.rect.left,right:("left"==k?l.left:l.right)-b.rect.left,top:t,bottom:u};return l.left||l.right||(v.bogus=!0),a.options.singleCursorHeightPerLine||(v.rtop=p,v.rbottom=q),v}function Cb(a,b){if(!window.screen||null==screen.logicalXDPI||screen.logicalXDPI==screen.deviceXDPI||!Mg(a))return b;var c=screen.logicalXDPI/screen.deviceXDPI,d=screen.logicalYDPI/screen.deviceYDPI;return{left:b.left*c,right:b.right*c,top:b.top*d,bottom:b.bottom*d}}function Db(a){if(a.measure&&(a.measure.cache={},a.measure.heights=null,a.rest))for(var b=0;b<a.rest.length;b++)a.measure.caches[b]={}}function Eb(a){a.display.externalMeasure=null,rg(a.display.lineMeasure);for(var b=0;b<a.display.view.length;b++)Db(a.display.view[b])}function Fb(a){Eb(a),a.display.cachedCharWidth=a.display.cachedTextHeight=a.display.cachedPaddingH=null,a.options.lineWrapping||(a.display.maxLineChanged=!0),a.display.lineNumChars=null}function Gb(){return window.pageXOffset||(document.documentElement||document.body).scrollLeft}function Hb(){return window.pageYOffset||(document.documentElement||document.body).scrollTop}function Ib(a,b,c,d){if(b.widgets)for(var e=0;e<b.widgets.length;++e)if(b.widgets[e].above){var f=Ae(b.widgets[e]);c.top+=f,c.bottom+=f}if("line"==d)return c;d||(d="local");var g=mf(b);if("local"==d?g+=mb(a.display):g-=a.display.viewOffset,"page"==d||"window"==d){var h=a.display.lineSpace.getBoundingClientRect();g+=h.top+("window"==d?0:Hb());var i=h.left+("window"==d?0:Gb());c.left+=i,c.right+=i}return c.top+=g,c.bottom+=g,c}function Jb(a,b,c){if("div"==c)return b;var d=b.left,e=b.top;if("page"==c)d-=Gb(),e-=Hb();else if("local"==c||!c){var f=a.display.sizer.getBoundingClientRect();d+=f.left,e+=f.top}var g=a.display.lineSpace.getBoundingClientRect();return{left:d-g.left,top:e-g.top}}function Kb(a,b,c,d,e){return d||(d=ff(a.doc,b.line)),Ib(a,d,vb(a,d,b.ch,e),c)}function Lb(a,b,c,d,e,f){function g(b,g){var h=yb(a,e,b,g?"right":"left",f);return g?h.left=h.right:h.right=h.left,Ib(a,d,h,c)}function h(a,b){var c=i[b],d=c.level%2;return a==Pg(c)&&b&&c.level<i[b-1].level?(c=i[--b],a=Qg(c)-(c.level%2?0:1),d=!0):a==Qg(c)&&b<i.length-1&&c.level<i[b+1].level&&(c=i[++b],a=Pg(c)-c.level%2,d=!1),d&&a==c.to&&a>c.from?g(a-1):g(a,d)}d=d||ff(a.doc,b.line),e||(e=xb(a,d));var i=nf(d),j=b.ch;if(!i)return g(j);var k=Yg(i,j),l=h(j,k);return null!=Xg&&(l.other=h(j,Xg)),l}function Mb(a,b){var c=0,b=Oa(a.doc,b);a.options.lineWrapping||(c=Sb(a.display)*b.ch);var d=ff(a.doc,b.line),e=mf(d)+mb(a.display);return{left:c,right:c,top:e,bottom:e+d.height}}function Nb(a,b,c,d){var e=oa(a,b);return e.xRel=d,c&&(e.outside=!0),e}function Ob(a,b,c){var d=a.doc;if(c+=a.display.viewOffset,0>c)return Nb(d.first,0,!0,-1);var e=lf(d,c),f=d.first+d.size-1;if(e>f)return Nb(d.first+d.size-1,ff(d,f).text.length,!0,1);0>b&&(b=0);for(var g=ff(d,e);;){var h=Pb(a,g,e,b,c),i=qe(g),j=i&&i.find(0,!0);if(!i||!(h.ch>j.from.ch||h.ch==j.from.ch&&h.xRel>0))return h;e=kf(g=j.to.line)}}function Pb(a,b,c,d,e){function j(d){var e=Lb(a,oa(c,d),"line",b,i);return g=!0,f>e.bottom?e.left-h:f<e.top?e.left+h:(g=!1,e.left)}var f=e-mf(b),g=!1,h=2*a.display.wrapper.clientWidth,i=xb(a,b),k=nf(b),l=b.text.length,m=Rg(b),n=Sg(b),o=j(m),p=g,q=j(n),r=g;if(d>q)return Nb(c,n,r,1);for(;;){if(k?n==m||n==$g(b,m,1):1>=n-m){for(var s=o>d||q-d>=d-o?m:n,t=d-(s==m?o:q);og(b.text.charAt(s));)++s;var u=Nb(c,s,s==m?p:r,-1>t?-1:t>1?1:0);return u}var v=Math.ceil(l/2),w=m+v;if(k){w=m;for(var x=0;v>x;++x)w=$g(b,w,1)}var y=j(w);y>d?(n=w,q=y,(r=g)&&(q+=1e3),l=v):(m=w,o=y,p=g,l-=v)}}function Rb(a){if(null!=a.cachedTextHeight)return a.cachedTextHeight;if(null==Qb){Qb=pg("pre");for(var b=0;49>b;++b)Qb.appendChild(document.createTextNode("x")),Qb.appendChild(pg("br"));Qb.appendChild(document.createTextNode("x"))}sg(a.measure,Qb);var c=Qb.offsetHeight/50;return c>3&&(a.cachedTextHeight=c),rg(a.measure),c||1}function Sb(a){if(null!=a.cachedCharWidth)return a.cachedCharWidth;var b=pg("span","xxxxxxxxxx"),c=pg("pre",[b]);sg(a.measure,c);var d=b.getBoundingClientRect(),e=(d.right-d.left)/10;return e>2&&(a.cachedCharWidth=e),e||10}function Vb(a){a.curOp={cm:a,viewChanged:!1,startHeight:a.doc.height,forceUpdate:!1,updateInput:null,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++Ub},Tb?Tb.ops.push(a.curOp):a.curOp.ownsGroup=Tb={ops:[a.curOp],delayedCallbacks:[]}}function Wb(a){var b=a.delayedCallbacks,c=0;do{for(;c<b.length;c++)b[c].call(null);for(var d=0;d<a.ops.length;d++){var e=a.ops[d];if(e.cursorActivityHandlers)for(;e.cursorActivityCalled<e.cursorActivityHandlers.length;)e.cursorActivityHandlers[e.cursorActivityCalled++].call(null,e.cm)}}while(c<b.length)}function Xb(a){var b=a.curOp,c=b.ownsGroup;if(c)try{Wb(c)}finally{Tb=null;for(var d=0;d<c.ops.length;d++)c.ops[d].cm.curOp=null;Yb(c)}}function Yb(a){for(var b=a.ops,c=0;c<b.length;c++)Zb(b[c]);for(var c=0;c<b.length;c++)$b(b[c]);for(var c=0;c<b.length;c++)_b(b[c]);for(var c=0;c<b.length;c++)ac(b[c]);for(var c=0;c<b.length;c++)bc(b[c])}function Zb(a){var b=a.cm,c=b.display;V(b),a.updateMaxLine&&H(b),a.mustUpdate=a.viewChanged||a.forceUpdate||null!=a.scrollTop||a.scrollToPos&&(a.scrollToPos.from.line<c.viewFrom||a.scrollToPos.to.line>=c.viewTo)||c.maxLineChanged&&b.options.lineWrapping,a.update=a.mustUpdate&&new U(b,a.mustUpdate&&{top:a.scrollTop,ensure:a.scrollToPos},a.forceUpdate)}function $b(a){a.updatedDisplay=a.mustUpdate&&W(a.cm,a.update)}function _b(a){var b=a.cm,c=b.display;a.updatedDisplay&&$(b),a.barMeasure=J(b),c.maxLineChanged&&!b.options.lineWrapping&&(a.adjustWidthTo=vb(b,c.maxLine,c.maxLine.text.length).left+3,b.display.sizerWidth=a.adjustWidthTo,a.barMeasure.scrollWidth=Math.max(c.scroller.clientWidth,c.sizer.offsetLeft+a.adjustWidthTo+pb(b)+b.display.barWidth),a.maxScrollLeft=Math.max(0,c.sizer.offsetLeft+a.adjustWidthTo-qb(b))),(a.updatedDisplay||a.selectionChanged)&&(a.preparedSelection=c.input.prepareSelection())}function ac(a){var b=a.cm;null!=a.adjustWidthTo&&(b.display.sizer.style.minWidth=a.adjustWidthTo+"px",a.maxScrollLeft<b.doc.scrollLeft&&Ic(b,Math.min(b.display.scroller.scrollLeft,a.maxScrollLeft),!0),b.display.maxLineChanged=!1),a.preparedSelection&&b.display.input.showSelection(a.preparedSelection),a.updatedDisplay&&Z(b,a.barMeasure),(a.updatedDisplay||a.startHeight!=b.doc.height)&&N(b,a.barMeasure),a.selectionChanged&&hb(b),b.state.focused&&a.updateInput&&b.display.input.reset(a.typing),a.focus&&a.focus==ug()&&ta(a.cm)}function bc(a){var b=a.cm,c=b.display,d=b.doc;if(a.updatedDisplay&&X(b,a.update),null==c.wheelStartX||null==a.scrollTop&&null==a.scrollLeft&&!a.scrollToPos||(c.wheelStartX=c.wheelStartY=null),null==a.scrollTop||c.scroller.scrollTop==a.scrollTop&&!a.forceScroll||(d.scrollTop=Math.max(0,Math.min(c.scroller.scrollHeight-c.scroller.clientHeight,a.scrollTop)),c.scrollbars.setScrollTop(d.scrollTop),c.scroller.scrollTop=d.scrollTop),null==a.scrollLeft||c.scroller.scrollLeft==a.scrollLeft&&!a.forceScroll||(d.scrollLeft=Math.max(0,Math.min(c.scroller.scrollWidth-qb(b),a.scrollLeft)),c.scrollbars.setScrollLeft(d.scrollLeft),c.scroller.scrollLeft=d.scrollLeft,Q(b)),a.scrollToPos){var e=pd(b,Oa(d,a.scrollToPos.from),Oa(d,a.scrollToPos.to),a.scrollToPos.margin);a.scrollToPos.isCursor&&b.state.focused&&od(b,e)}var f=a.maybeHiddenMarkers,g=a.maybeUnhiddenMarkers;if(f)for(var h=0;h<f.length;++h)f[h].lines.length||Lf(f[h],"hide");if(g)for(var h=0;h<g.length;++h)g[h].lines.length&&Lf(g[h],"unhide");c.wrapper.offsetHeight&&(d.scrollTop=b.display.scroller.scrollTop),a.changeObjs&&Lf(b,"changes",b,a.changeObjs),a.update&&a.update.finish()}function cc(a,b){if(a.curOp)return b();Vb(a);try{return b()}finally{Xb(a)}}function dc(a,b){return function(){if(a.curOp)return b.apply(a,arguments);Vb(a);try{return b.apply(a,arguments)}finally{Xb(a)}}}function ec(a){return function(){if(this.curOp)return a.apply(this,arguments);Vb(this);try{return a.apply(this,arguments)}finally{Xb(this)}}}function fc(a){return function(){var b=this.cm;if(!b||b.curOp)return a.apply(this,arguments);Vb(b);try{return a.apply(this,arguments)}finally{Xb(b)}}}function gc(a,b,c){this.line=b,this.rest=te(b),this.size=this.rest?kf(bg(this.rest))-c+1:1,this.node=this.text=null,this.hidden=we(a,b)}function hc(a,b,c){for(var e,d=[],f=b;c>f;f=e){var g=new gc(a.doc,ff(a.doc,f),f);e=f+g.size,d.push(g)}return d}function ic(a,b,c,d){null==b&&(b=a.doc.first),null==c&&(c=a.doc.first+a.doc.size),d||(d=0);var e=a.display;if(d&&c<e.viewTo&&(null==e.updateLineNumbers||e.updateLineNumbers>b)&&(e.updateLineNumbers=b),a.curOp.viewChanged=!0,b>=e.viewTo)u&&ue(a.doc,b)<e.viewTo&&kc(a);else if(c<=e.viewFrom)u&&ve(a.doc,c+d)>e.viewFrom?kc(a):(e.viewFrom+=d,e.viewTo+=d);else if(b<=e.viewFrom&&c>=e.viewTo)kc(a);else if(b<=e.viewFrom){var f=mc(a,c,c+d,1);f?(e.view=e.view.slice(f.index),e.viewFrom=f.lineN,e.viewTo+=d):kc(a)}else if(c>=e.viewTo){var f=mc(a,b,b,-1);f?(e.view=e.view.slice(0,f.index),e.viewTo=f.lineN):kc(a)}else{var g=mc(a,b,b,-1),h=mc(a,c,c+d,1);g&&h?(e.view=e.view.slice(0,g.index).concat(hc(a,g.lineN,h.lineN)).concat(e.view.slice(h.index)),e.viewTo+=d):kc(a)}var i=e.externalMeasured;i&&(c<i.lineN?i.lineN+=d:b<i.lineN+i.size&&(e.externalMeasured=null))}function jc(a,b,c){a.curOp.viewChanged=!0;var d=a.display,e=a.display.externalMeasured;if(e&&b>=e.lineN&&b<e.lineN+e.size&&(d.externalMeasured=null),!(b<d.viewFrom||b>=d.viewTo)){var f=d.view[lc(a,b)];if(null!=f.node){var g=f.changes||(f.changes=[]);-1==dg(g,c)&&g.push(c)}}}function kc(a){a.display.viewFrom=a.display.viewTo=a.doc.first,a.display.view=[],a.display.viewOffset=0}function lc(a,b){if(b>=a.display.viewTo)return null;if(b-=a.display.viewFrom,0>b)return null;for(var c=a.display.view,d=0;d<c.length;d++)if(b-=c[d].size,0>b)return d}function mc(a,b,c,d){var f,e=lc(a,b),g=a.display.view;if(!u||c==a.doc.first+a.doc.size)return{index:e,lineN:c};for(var h=0,i=a.display.viewFrom;e>h;h++)i+=g[h].size;if(i!=b){if(d>0){if(e==g.length-1)return null;f=i+g[e].size-b,e++}else f=i-b;b+=f,c+=f}for(;ue(a.doc,c)!=c;){if(e==(0>d?0:g.length-1))return null;c+=d*g[e-(0>d?1:0)].size,e+=d}return{index:e,lineN:c}}function nc(a,b,c){var d=a.display,e=d.view;0==e.length||b>=d.viewTo||c<=d.viewFrom?(d.view=hc(a,b,c),d.viewFrom=b):(d.viewFrom>b?d.view=hc(a,b,d.viewFrom).concat(d.view):d.viewFrom<b&&(d.view=d.view.slice(lc(a,b))),d.viewFrom=b,d.viewTo<c?d.view=d.view.concat(hc(a,d.viewTo,c)):d.viewTo>c&&(d.view=d.view.slice(0,lc(a,c)))),d.viewTo=c}function oc(a){for(var b=a.display.view,c=0,d=0;d<b.length;d++){var e=b[d];e.hidden||e.node&&!e.changes||++c}return c}function pc(a){function g(){b.activeTouch&&(c=setTimeout(function(){b.activeTouch=null},1e3),f=b.activeTouch,f.end=+new Date)}function h(a){if(1!=a.touches.length)return!1;var b=a.touches[0];return b.radiusX<=1&&b.radiusY<=1}function i(a,b){if(null==b.left)return!0;var c=b.left-a.left,d=b.top-a.top;return c*c+d*d>400}var b=a.display;Jf(b.scroller,"mousedown",dc(a,uc)),d&&11>e?Jf(b.scroller,"dblclick",dc(a,function(b){if(!Pf(a,b)){var c=tc(a,b);if(c&&!Bc(a,b)&&!sc(a.display,b)){Df(b);var d=a.findWordAt(c);Ta(a.doc,d.anchor,d.head)}}})):Jf(b.scroller,"dblclick",function(b){Pf(a,b)||Df(b)}),s||Jf(b.scroller,"contextmenu",function(b){_c(a,b)});var c,f={end:0};Jf(b.scroller,"touchstart",function(a){if(!h(a)){clearTimeout(c);var d=+new Date;b.activeTouch={start:d,moved:!1,prev:d-f.end<=300?f:null},1==a.touches.length&&(b.activeTouch.left=a.touches[0].pageX,b.activeTouch.top=a.touches[0].pageY)}}),Jf(b.scroller,"touchmove",function(){b.activeTouch&&(b.activeTouch.moved=!0)}),Jf(b.scroller,"touchend",function(c){var d=b.activeTouch;if(d&&!sc(b,c)&&null!=d.left&&!d.moved&&new Date-d.start<300){var f,e=a.coordsChar(b.activeTouch,"page");f=!d.prev||i(d,d.prev)?new Ka(e,e):!d.prev.prev||i(d,d.prev.prev)?a.findWordAt(e):new Ka(oa(e.line,0),Oa(a.doc,oa(e.line+1,0))),a.setSelection(f.anchor,f.head),a.focus(),Df(c)}g()}),Jf(b.scroller,"touchcancel",g),Jf(b.scroller,"scroll",function(){b.scroller.clientHeight&&(Hc(a,b.scroller.scrollTop),Ic(a,b.scroller.scrollLeft,!0),Lf(a,"scroll",a))}),Jf(b.scroller,"mousewheel",function(b){Mc(a,b)}),Jf(b.scroller,"DOMMouseScroll",function(b){Mc(a,b)}),Jf(b.wrapper,"scroll",function(){b.wrapper.scrollTop=b.wrapper.scrollLeft=0}),b.dragFunctions={enter:function(b){Pf(a,b)||Gf(b)},over:function(b){Pf(a,b)||(Fc(a,b),Gf(b))},start:function(b){Ec(a,b)},drop:dc(a,Dc),leave:function(){Gc(a)}};var j=b.input.getField();Jf(j,"keyup",function(b){Wc.call(a,b)}),Jf(j,"keydown",dc(a,Uc)),Jf(j,"keypress",dc(a,Xc)),Jf(j,"focus",ig(Zc,a)),Jf(j,"blur",ig($c,a))}function qc(a,b,c){var d=c&&c!=v.Init;if(!b!=!d){var e=a.display.dragFunctions,f=b?Jf:Kf;f(a.display.scroller,"dragstart",e.start),f(a.display.scroller,"dragenter",e.enter),f(a.display.scroller,"dragover",e.over),f(a.display.scroller,"dragleave",e.leave),f(a.display.scroller,"drop",e.drop)}}function rc(a){var b=a.display;(b.lastWrapHeight!=b.wrapper.clientHeight||b.lastWrapWidth!=b.wrapper.clientWidth)&&(b.cachedCharWidth=b.cachedTextHeight=b.cachedPaddingH=null,b.scrollbarsClipped=!1,a.setSize())}function sc(a,b){for(var c=Hf(b);c!=a.wrapper;c=c.parentNode)if(!c||1==c.nodeType&&"true"==c.getAttribute("cm-ignore-events")||c.parentNode==a.sizer&&c!=a.mover)return!0}function tc(a,b,c,d){var e=a.display;if(!c&&"true"==Hf(b).getAttribute("cm-not-content"))return null;var f,g,h=e.lineSpace.getBoundingClientRect();try{f=b.clientX-h.left,g=b.clientY-h.top}catch(b){return null}var j,i=Ob(a,f,g);if(d&&1==i.xRel&&(j=ff(a.doc,i.line).text).length==i.ch){var k=Zf(j,j.length,a.options.tabSize)-j.length;i=oa(i.line,Math.max(0,Math.round((f-ob(a.display).left)/Sb(a.display))-k))}return i}function uc(a){var b=this,c=b.display;if(!(c.activeTouch&&c.input.supportsTouch()||Pf(b,a))){if(c.shift=a.shiftKey,sc(c,a))return void(f||(c.scroller.draggable=!1,setTimeout(function(){c.scroller.draggable=!0},100)));if(!Bc(b,a)){var d=tc(b,a);switch(window.focus(),If(a)){case 1:b.state.selectingText?b.state.selectingText(a):d?xc(b,a,d):Hf(a)==c.scroller&&Df(a);break;case 2:f&&(b.state.lastMiddleDown=+new Date),d&&Ta(b.doc,d),setTimeout(function(){c.input.focus()},20),Df(a);break;case 3:s?_c(b,a):Yc(b)}}}}function xc(a,b,c){d?setTimeout(ig(ta,a),0):a.curOp.focus=ug();var f,e=+new Date;wc&&wc.time>e-400&&0==pa(wc.pos,c)?f="triple":vc&&vc.time>e-400&&0==pa(vc.pos,c)?(f="double",wc={time:e,pos:c}):(f="single",vc={time:e,pos:c});var i,g=a.doc.sel,h=o?b.metaKey:b.ctrlKey;a.options.dragDrop&&Dg&&!ua(a)&&"single"==f&&(i=g.contains(c))>-1&&(pa((i=g.ranges[i]).from(),c)<0||c.xRel>0)&&(pa(i.to(),c)>0||c.xRel<0)?yc(a,b,c,h):zc(a,b,c,f,h)}function yc(a,b,c,g){var h=a.display,i=+new Date,j=dc(a,function(k){f&&(h.scroller.draggable=!1),a.state.draggingText=!1,Kf(document,"mouseup",j),Kf(h.scroller,"drop",j),Math.abs(b.clientX-k.clientX)+Math.abs(b.clientY-k.clientY)<10&&(Df(k),!g&&+new Date-200<i&&Ta(a.doc,c),f||d&&9==e?setTimeout(function(){document.body.focus(),h.input.focus()},20):h.input.focus())});f&&(h.scroller.draggable=!0),a.state.draggingText=j,h.scroller.dragDrop&&h.scroller.dragDrop(),Jf(document,"mouseup",j),Jf(h.scroller,"drop",j)}function zc(a,b,c,d,e){function o(b){if(0!=pa(n,b))if(n=b,"rect"==d){for(var e=[],f=a.options.tabSize,k=Zf(ff(g,c.line).text,c.ch,f),l=Zf(ff(g,b.line).text,b.ch,f),m=Math.min(k,l),o=Math.max(k,l),p=Math.min(c.line,b.line),q=Math.min(a.lastLine(),Math.max(c.line,b.line));q>=p;p++){var r=ff(g,p).text,s=$f(r,m,f);m==o?e.push(new Ka(oa(p,s),oa(p,s))):r.length>s&&e.push(new Ka(oa(p,s),oa(p,$f(r,o,f))))}e.length||e.push(new Ka(c,c)),Za(g,La(j.ranges.slice(0,i).concat(e),i),{origin:"*mouse",scroll:!1}),a.scrollIntoView(b)}else{var t=h,u=t.anchor,v=b;if("single"!=d){if("double"==d)var w=a.findWordAt(b);else var w=new Ka(oa(b.line,0),Oa(g,oa(b.line+1,0)));pa(w.anchor,u)>0?(v=w.head,u=sa(t.from(),w.anchor)):(v=w.anchor,u=ra(t.to(),w.head))}var e=j.ranges.slice(0);e[i]=new Ka(Oa(g,u),v),Za(g,La(e,i),Wf)}}function r(b){var c=++q,e=tc(a,b,!0,"rect"==d);if(e)if(0!=pa(e,n)){a.curOp.focus=ug(),o(e);var h=P(f,g);(e.line>=h.to||e.line<h.from)&&setTimeout(dc(a,function(){q==c&&r(b)}),150)}else{var i=b.clientY<p.top?-20:b.clientY>p.bottom?20:0;i&&setTimeout(dc(a,function(){q==c&&(f.scroller.scrollTop+=i,r(b))}),50)}}function s(b){a.state.selectingText=!1,q=1/0,Df(b),f.input.focus(),Kf(document,"mousemove",t),Kf(document,"mouseup",u),g.history.lastSelOrigin=null}var f=a.display,g=a.doc;Df(b);var h,i,j=g.sel,k=j.ranges;if(e&&!b.shiftKey?(i=g.sel.contains(c),h=i>-1?k[i]:new Ka(c,c)):(h=g.sel.primary(),i=g.sel.primIndex),b.altKey)d="rect",e||(h=new Ka(c,c)),c=tc(a,b,!0,!0),i=-1;else if("double"==d){var l=a.findWordAt(c);h=a.display.shift||g.extend?Sa(g,h,l.anchor,l.head):l}else if("triple"==d){var m=new Ka(oa(c.line,0),Oa(g,oa(c.line+1,0)));h=a.display.shift||g.extend?Sa(g,h,m.anchor,m.head):m}else h=Sa(g,h,c);e?-1==i?(i=k.length,Za(g,La(k.concat([h]),i),{scroll:!1,origin:"*mouse"})):k.length>1&&k[i].empty()&&"single"==d&&!b.shiftKey?(Za(g,La(k.slice(0,i).concat(k.slice(i+1)),0),{scroll:!1,origin:"*mouse"}),j=g.sel):Va(g,i,h,Wf):(i=0,Za(g,new Ja([h],0),Wf),j=g.sel);var n=c,p=f.wrapper.getBoundingClientRect(),q=0,t=dc(a,function(a){If(a)?r(a):s(a)}),u=dc(a,s);a.state.selectingText=u,Jf(document,"mousemove",t),Jf(document,"mouseup",u)}function Ac(a,b,c,d,e){try{var f=b.clientX,g=b.clientY}catch(b){return!1}if(f>=Math.floor(a.display.gutters.getBoundingClientRect().right))return!1;d&&Df(b);var h=a.display,i=h.lineDiv.getBoundingClientRect();if(g>i.bottom||!Rf(a,c))return Ff(b);g-=i.top-h.viewOffset;for(var j=0;j<a.options.gutters.length;++j){var k=h.gutters.childNodes[j];if(k&&k.getBoundingClientRect().right>=f){var l=lf(a.doc,g),m=a.options.gutters[j];return e(a,c,a,l,m,b),Ff(b)}}}function Bc(a,b){return Ac(a,b,"gutterClick",!0,Nf)}function Dc(a){var b=this;if(Gc(b),!Pf(b,a)&&!sc(b.display,a)){Df(a),d&&(Cc=+new Date);var c=tc(b,a,!0),e=a.dataTransfer.files;if(c&&!ua(b))if(e&&e.length&&window.FileReader&&window.File)for(var f=e.length,g=Array(f),h=0,i=function(a,d){var e=new FileReader;e.onload=dc(b,function(){if(g[d]=e.result,++h==f){c=Oa(b.doc,c);var a={from:c,to:c,text:b.doc.splitLines(g.join(b.doc.lineSeparator())),origin:"paste"};hd(b.doc,a),Ya(b.doc,Ma(c,bd(a)))}}),e.readAsText(a)},j=0;f>j;++j)i(e[j],j);else{if(b.state.draggingText&&b.doc.sel.contains(c)>-1)return b.state.draggingText(a),void setTimeout(function(){b.display.input.focus()},20);try{var g=a.dataTransfer.getData("Text");if(g){if(b.state.draggingText&&!(o?a.altKey:a.ctrlKey))var k=b.listSelections();if($a(b.doc,Ma(c,c)),k)for(var j=0;j<k.length;++j)nd(b.doc,"",k[j].anchor,k[j].head,"drag");b.replaceSelection(g,"around","paste"),b.display.input.focus()}}catch(a){}}}}function Ec(a,b){if(d&&(!a.state.draggingText||+new Date-Cc<100))return void Gf(b);if(!Pf(a,b)&&!sc(a.display,b)&&(b.dataTransfer.setData("Text",a.getSelection()),b.dataTransfer.setDragImage&&!j)){var c=pg("img",null,null,"position: fixed; left: 0; top: 0;");c.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",i&&(c.width=c.height=1,a.display.wrapper.appendChild(c),c._top=c.offsetTop),b.dataTransfer.setDragImage(c,0,0),i&&c.parentNode.removeChild(c)}}function Fc(a,b){var c=tc(a,b);if(c){var d=document.createDocumentFragment();fb(a,c,d),a.display.dragCursor||(a.display.dragCursor=pg("div",null,"CodeMirror-cursors CodeMirror-dragcursors"),a.display.lineSpace.insertBefore(a.display.dragCursor,a.display.cursorDiv)),sg(a.display.dragCursor,d)}}function Gc(a){a.display.dragCursor&&(a.display.lineSpace.removeChild(a.display.dragCursor),a.display.dragCursor=null)}function Hc(b,c){Math.abs(b.doc.scrollTop-c)<2||(b.doc.scrollTop=c,a||Y(b,{top:c}),b.display.scroller.scrollTop!=c&&(b.display.scroller.scrollTop=c),b.display.scrollbars.setScrollTop(c),a&&Y(b),ib(b,100))}function Ic(a,b,c){(c?b==a.doc.scrollLeft:Math.abs(a.doc.scrollLeft-b)<2)||(b=Math.min(b,a.display.scroller.scrollWidth-a.display.scroller.clientWidth),a.doc.scrollLeft=b,Q(a),a.display.scroller.scrollLeft!=b&&(a.display.scroller.scrollLeft=b),a.display.scrollbars.setScrollLeft(b))}function Mc(b,c){var d=Lc(c),e=d.x,g=d.y,h=b.display,j=h.scroller;if(e&&j.scrollWidth>j.clientWidth||g&&j.scrollHeight>j.clientHeight){if(g&&o&&f)a:for(var k=c.target,l=h.view;k!=j;k=k.parentNode)for(var m=0;m<l.length;m++)if(l[m].node==k){b.display.currentWheelTarget=k;break a}if(e&&!a&&!i&&null!=Kc)return g&&Hc(b,Math.max(0,Math.min(j.scrollTop+g*Kc,j.scrollHeight-j.clientHeight))),Ic(b,Math.max(0,Math.min(j.scrollLeft+e*Kc,j.scrollWidth-j.clientWidth))),Df(c),void(h.wheelStartX=null);if(g&&null!=Kc){var n=g*Kc,p=b.doc.scrollTop,q=p+h.wrapper.clientHeight;0>n?p=Math.max(0,p+n-50):q=Math.min(b.doc.height,q+n+50),Y(b,{top:p,bottom:q})}20>Jc&&(null==h.wheelStartX?(h.wheelStartX=j.scrollLeft,h.wheelStartY=j.scrollTop,h.wheelDX=e,h.wheelDY=g,setTimeout(function(){if(null!=h.wheelStartX){var a=j.scrollLeft-h.wheelStartX,b=j.scrollTop-h.wheelStartY,c=b&&h.wheelDY&&b/h.wheelDY||a&&h.wheelDX&&a/h.wheelDX;h.wheelStartX=h.wheelStartY=null,c&&(Kc=(Kc*Jc+c)/(Jc+1),++Jc)}},200)):(h.wheelDX+=e,h.wheelDY+=g))}}function Nc(a,b,c){if("string"==typeof b&&(b=Ld[b],!b))return!1;a.display.input.ensurePolled();var d=a.display.shift,e=!1;try{ua(a)&&(a.state.suppressEdits=!0),c&&(a.display.shift=!1),e=b(a)!=Uf}finally{a.display.shift=d,a.state.suppressEdits=!1}return e}function Oc(a,b,c){for(var d=0;d<a.state.keyMaps.length;d++){var e=Od(b,a.state.keyMaps[d],c,a);if(e)return e}return a.options.extraKeys&&Od(b,a.options.extraKeys,c,a)||Od(b,a.options.keyMap,c,a)}function Qc(a,b,c,d){var e=a.state.keySeq;if(e){if(Pd(b))return"handled";Pc.set(50,function(){a.state.keySeq==e&&(a.state.keySeq=null,a.display.input.reset())}),b=e+" "+b}var f=Oc(a,b,d);return"multi"==f&&(a.state.keySeq=b),"handled"==f&&Nf(a,"keyHandled",a,b,c),("handled"==f||"multi"==f)&&(Df(c),hb(a)),e&&!f&&/\'$/.test(b)?(Df(c),!0):!!f}function Rc(a,b){var c=Qd(b,!0);return c?b.shiftKey&&!a.state.keySeq?Qc(a,"Shift-"+c,b,function(b){return Nc(a,b,!0)})||Qc(a,c,b,function(b){return("string"==typeof b?/^go[A-Z]/.test(b):b.motion)?Nc(a,b):void 0}):Qc(a,c,b,function(b){return Nc(a,b)}):!1}function Sc(a,b,c){return Qc(a,"'"+c+"'",b,function(b){return Nc(a,b,!0)})}function Uc(a){var b=this;if(b.curOp.focus=ug(),!Pf(b,a)){d&&11>e&&27==a.keyCode&&(a.returnValue=!1);var c=a.keyCode;b.display.shift=16==c||a.shiftKey;var f=Rc(b,a);i&&(Tc=f?c:null,!f&&88==c&&!Kg&&(o?a.metaKey:a.ctrlKey)&&b.replaceSelection("",null,"cut")),18!=c||/\bCodeMirror-crosshair\b/.test(b.display.lineDiv.className)||Vc(b)}}function Vc(a){function c(a){18!=a.keyCode&&a.altKey||(wg(b,"CodeMirror-crosshair"),Kf(document,"keyup",c),Kf(document,"mouseover",c))}var b=a.display.lineDiv;xg(b,"CodeMirror-crosshair"),Jf(document,"keyup",c),Jf(document,"mouseover",c)}function Wc(a){16==a.keyCode&&(this.doc.sel.shift=!1),Pf(this,a)}function Xc(a){var b=this;if(!(sc(b.display,a)||Pf(b,a)||a.ctrlKey&&!a.altKey||o&&a.metaKey)){var c=a.keyCode,d=a.charCode;if(i&&c==Tc)return Tc=null,void Df(a);if(!i||a.which&&!(a.which<10)||!Rc(b,a)){var e=String.fromCharCode(null==d?c:d);Sc(b,a,e)||b.display.input.onKeyPress(a)}}}function Yc(a){a.state.delayingBlurEvent=!0,setTimeout(function(){a.state.delayingBlurEvent&&(a.state.delayingBlurEvent=!1,$c(a))},100)}function Zc(a){a.state.delayingBlurEvent&&(a.state.delayingBlurEvent=!1),"nocursor"!=a.options.readOnly&&(a.state.focused||(Lf(a,"focus",a),a.state.focused=!0,xg(a.display.wrapper,"CodeMirror-focused"),a.curOp||a.display.selForContextMenu==a.doc.sel||(a.display.input.reset(),f&&setTimeout(function(){a.display.input.reset(!0)},20)),a.display.input.receivedFocus()),hb(a))}function $c(a){a.state.delayingBlurEvent||(a.state.focused&&(Lf(a,"blur",a),a.state.focused=!1,wg(a.display.wrapper,"CodeMirror-focused")),clearInterval(a.display.blinker),setTimeout(function(){a.state.focused||(a.display.shift=!1)},150))}function _c(a,b){sc(a.display,b)||ad(a,b)||a.display.input.onContextMenu(b)}function ad(a,b){return Rf(a,"gutterContextMenu")?Ac(a,b,"gutterContextMenu",!1,Lf):!1}function cd(a,b){if(pa(a,b.from)<0)return a;if(pa(a,b.to)<=0)return bd(b);var c=a.line+b.text.length-(b.to.line-b.from.line)-1,d=a.ch;return a.line==b.to.line&&(d+=bd(b).ch-b.to.ch),oa(c,d)}function dd(a,b){for(var c=[],d=0;d<a.sel.ranges.length;d++){var e=a.sel.ranges[d];c.push(new Ka(cd(e.anchor,b),cd(e.head,b)))}return La(c,a.sel.primIndex)}function ed(a,b,c){return a.line==b.line?oa(c.line,a.ch-b.ch+c.ch):oa(c.line+(a.line-b.line),a.ch)}function fd(a,b,c){for(var d=[],e=oa(a.first,0),f=e,g=0;g<b.length;g++){var h=b[g],i=ed(h.from,e,f),j=ed(bd(h),e,f);if(e=h.to,f=j,"around"==c){var k=a.sel.ranges[g],l=pa(k.head,k.anchor)<0;d[g]=new Ka(l?j:i,l?i:j)}else d[g]=new Ka(i,i)}return new Ja(d,a.sel.primIndex)}function gd(a,b,c){var d={canceled:!1,from:b.from,to:b.to,text:b.text,origin:b.origin,cancel:function(){this.canceled=!0}};return c&&(d.update=function(b,c,d,e){b&&(this.from=Oa(a,b)),c&&(this.to=Oa(a,c)),d&&(this.text=d),void 0!==e&&(this.origin=e)}),Lf(a,"beforeChange",a,d),a.cm&&Lf(a.cm,"beforeChange",a.cm,d),d.canceled?null:{from:d.from,to:d.to,text:d.text,origin:d.origin}}function hd(a,b,c){if(a.cm){if(!a.cm.curOp)return dc(a.cm,hd)(a,b,c);if(a.cm.state.suppressEdits)return}if(!(Rf(a,"beforeChange")||a.cm&&Rf(a.cm,"beforeChange"))||(b=gd(a,b,!0))){var d=t&&!c&&ie(a,b.from,b.to);if(d)for(var e=d.length-1;e>=0;--e)id(a,{from:d[e].from,to:d[e].to,text:e?[""]:b.text});else id(a,b)}}function id(a,b){if(1!=b.text.length||""!=b.text[0]||0!=pa(b.from,b.to)){var c=dd(a,b);sf(a,b,c,a.cm?a.cm.curOp.id:NaN),ld(a,b,c,fe(a,b));var d=[];df(a,function(a,c){c||-1!=dg(d,a.history)||(Cf(a.history,b),d.push(a.history)),ld(a,b,null,fe(a,b))})}}function jd(a,b,c){if(!a.cm||!a.cm.state.suppressEdits){for(var e,d=a.history,f=a.sel,g="undo"==b?d.done:d.undone,h="undo"==b?d.undone:d.done,i=0;i<g.length&&(e=g[i],c?!e.ranges||e.equals(a.sel):e.ranges);i++);if(i!=g.length){for(d.lastOrigin=d.lastSelOrigin=null;e=g.pop(),e.ranges;){if(vf(e,h),c&&!e.equals(a.sel))return void Za(a,e,{clearRedo:!1});f=e}var j=[];vf(f,h),h.push({changes:j,generation:d.generation}),d.generation=e.generation||++d.maxGeneration;for(var k=Rf(a,"beforeChange")||a.cm&&Rf(a.cm,"beforeChange"),i=e.changes.length-1;i>=0;--i){var l=e.changes[i];if(l.origin=b,k&&!gd(a,l,!1))return void(g.length=0);j.push(pf(a,l));var m=i?dd(a,l):bg(g);ld(a,l,m,he(a,l)),!i&&a.cm&&a.cm.scrollIntoView({from:l.from,to:bd(l)});var n=[];df(a,function(a,b){b||-1!=dg(n,a.history)||(Cf(a.history,l),n.push(a.history)),ld(a,l,null,he(a,l))})}}}}function kd(a,b){if(0!=b&&(a.first+=b,a.sel=new Ja(eg(a.sel.ranges,function(a){return new Ka(oa(a.anchor.line+b,a.anchor.ch),oa(a.head.line+b,a.head.ch))}),a.sel.primIndex),a.cm)){ic(a.cm,a.first,a.first-b,b);for(var c=a.cm.display,d=c.viewFrom;d<c.viewTo;d++)jc(a.cm,d,"gutter")}}function ld(a,b,c,d){if(a.cm&&!a.cm.curOp)return dc(a.cm,ld)(a,b,c,d);if(b.to.line<a.first)return void kd(a,b.text.length-1-(b.to.line-b.from.line));if(!(b.from.line>a.lastLine())){if(b.from.line<a.first){var e=b.text.length-1-(a.first-b.from.line);kd(a,e),b={from:oa(a.first,0),to:oa(b.to.line+e,b.to.ch),text:[bg(b.text)],origin:b.origin}}var f=a.lastLine();b.to.line>f&&(b={from:b.from,to:oa(f,ff(a,f).text.length),text:[b.text[0]],origin:b.origin}),b.removed=gf(a,b.from,b.to),c||(c=dd(a,b)),a.cm?md(a.cm,b,d):Ye(a,b,d),$a(a,c,Vf)}}function md(a,b,c){var d=a.doc,e=a.display,f=b.from,g=b.to,h=!1,i=f.line;a.options.lineWrapping||(i=kf(se(ff(d,f.line))),d.iter(i,g.line+1,function(a){return a==e.maxLine?(h=!0,!0):void 0})),d.sel.contains(b.from,b.to)>-1&&Qf(a),Ye(d,b,c,A(a)),a.options.lineWrapping||(d.iter(i,f.line+b.text.length,function(a){var b=G(a);b>e.maxLineLength&&(e.maxLine=a,e.maxLineLength=b,e.maxLineChanged=!0,h=!1)}),h&&(a.curOp.updateMaxLine=!0)),d.frontier=Math.min(d.frontier,f.line),ib(a,400);var j=b.text.length-(g.line-f.line)-1;b.full?ic(a):f.line!=g.line||1!=b.text.length||Xe(a.doc,b)?ic(a,f.line,g.line+1,j):jc(a,f.line,"text");var k=Rf(a,"changes"),l=Rf(a,"change");if(l||k){var m={from:f,to:g,text:b.text,removed:b.removed,origin:b.origin};l&&Nf(a,"change",a,m),k&&(a.curOp.changeObjs||(a.curOp.changeObjs=[])).push(m)}a.display.selForContextMenu=null}function nd(a,b,c,d,e){if(d||(d=c),pa(d,c)<0){var f=d;d=c,c=f}"string"==typeof b&&(b=a.splitLines(b)),hd(a,{from:c,to:d,text:b,origin:e})}function od(a,b){if(!Pf(a,"scrollCursorIntoView")){var c=a.display,d=c.sizer.getBoundingClientRect(),e=null;if(b.top+d.top<0?e=!0:b.bottom+d.top>(window.innerHeight||document.documentElement.clientHeight)&&(e=!1),null!=e&&!l){var f=pg("div","\u200b",null,"position: absolute; top: "+(b.top-c.viewOffset-mb(a.display))+"px; height: "+(b.bottom-b.top+pb(a)+c.barHeight)+"px; left: "+b.left+"px; width: 2px;");a.display.lineSpace.appendChild(f),f.scrollIntoView(e),a.display.lineSpace.removeChild(f)}}}function pd(a,b,c,d){null==d&&(d=0);for(var e=0;5>e;e++){var f=!1,g=Lb(a,b),h=c&&c!=b?Lb(a,c):g,i=rd(a,Math.min(g.left,h.left),Math.min(g.top,h.top)-d,Math.max(g.left,h.left),Math.max(g.bottom,h.bottom)+d),j=a.doc.scrollTop,k=a.doc.scrollLeft;if(null!=i.scrollTop&&(Hc(a,i.scrollTop),Math.abs(a.doc.scrollTop-j)>1&&(f=!0)),null!=i.scrollLeft&&(Ic(a,i.scrollLeft),Math.abs(a.doc.scrollLeft-k)>1&&(f=!0)),!f)break}return g}function qd(a,b,c,d,e){var f=rd(a,b,c,d,e);null!=f.scrollTop&&Hc(a,f.scrollTop),null!=f.scrollLeft&&Ic(a,f.scrollLeft)}function rd(a,b,c,d,e){var f=a.display,g=Rb(a.display);0>c&&(c=0);var h=a.curOp&&null!=a.curOp.scrollTop?a.curOp.scrollTop:f.scroller.scrollTop,i=rb(a),j={};e-c>i&&(e=c+i);var k=a.doc.height+nb(f),l=g>c,m=e>k-g;if(h>c)j.scrollTop=l?0:c;else if(e>h+i){var n=Math.min(c,(m?k:e)-i);n!=h&&(j.scrollTop=n)}var o=a.curOp&&null!=a.curOp.scrollLeft?a.curOp.scrollLeft:f.scroller.scrollLeft,p=qb(a)-(a.options.fixedGutter?f.gutters.offsetWidth:0),q=d-b>p;return q&&(d=b+p),10>b?j.scrollLeft=0:o>b?j.scrollLeft=Math.max(0,b-(q?0:10)):d>p+o-3&&(j.scrollLeft=d+(q?0:10)-p),j}function sd(a,b,c){(null!=b||null!=c)&&ud(a),null!=b&&(a.curOp.scrollLeft=(null==a.curOp.scrollLeft?a.doc.scrollLeft:a.curOp.scrollLeft)+b),null!=c&&(a.curOp.scrollTop=(null==a.curOp.scrollTop?a.doc.scrollTop:a.curOp.scrollTop)+c)}function td(a){ud(a);var b=a.getCursor(),c=b,d=b;a.options.lineWrapping||(c=b.ch?oa(b.line,b.ch-1):b,d=oa(b.line,b.ch+1)),a.curOp.scrollToPos={from:c,to:d,margin:a.options.cursorScrollMargin,isCursor:!0}}function ud(a){var b=a.curOp.scrollToPos;if(b){a.curOp.scrollToPos=null;var c=Mb(a,b.from),d=Mb(a,b.to),e=rd(a,Math.min(c.left,d.left),Math.min(c.top,d.top)-b.margin,Math.max(c.right,d.right),Math.max(c.bottom,d.bottom)+b.margin);a.scrollTo(e.scrollLeft,e.scrollTop)}}function vd(a,b,c,d){var f,e=a.doc;null==c&&(c="add"),"smart"==c&&(e.mode.indent?f=lb(a,b):c="prev");var g=a.options.tabSize,h=ff(e,b),i=Zf(h.text,null,g);h.stateAfter&&(h.stateAfter=null);var k,j=h.text.match(/^\s*/)[0];if(d||/\S/.test(h.text)){if("smart"==c&&(k=e.mode.indent(f,h.text.slice(j.length),h.text),k==Uf||k>150)){if(!d)return;c="prev"}}else k=0,c="not";"prev"==c?k=b>e.first?Zf(ff(e,b-1).text,null,g):0:"add"==c?k=i+a.options.indentUnit:"subtract"==c?k=i-a.options.indentUnit:"number"==typeof c&&(k=i+c),k=Math.max(0,k);
+var l="",m=0;if(a.options.indentWithTabs)for(var n=Math.floor(k/g);n;--n)m+=g,l+="	";if(k>m&&(l+=ag(k-m)),l!=j)return nd(e,l,oa(b,0),oa(b,j.length),"+input"),h.stateAfter=null,!0;for(var n=0;n<e.sel.ranges.length;n++){var o=e.sel.ranges[n];if(o.head.line==b&&o.head.ch<j.length){var m=oa(b,j.length);Va(e,n,new Ka(m,m));break}}}function wd(a,b,c,d){var e=b,f=b;return"number"==typeof b?f=ff(a,Na(a,b)):e=kf(b),null==e?null:(d(f,e)&&a.cm&&jc(a.cm,e,c),f)}function xd(a,b){for(var c=a.doc.sel.ranges,d=[],e=0;e<c.length;e++){for(var f=b(c[e]);d.length&&pa(f.from,bg(d).to)<=0;){var g=d.pop();if(pa(g.from,f.from)<0){f.from=g.from;break}}d.push(f)}cc(a,function(){for(var b=d.length-1;b>=0;b--)nd(a.doc,"",d[b].from,d[b].to,"+delete");td(a)})}function yd(a,b,c,d,e){function k(){var b=f+c;return b<a.first||b>=a.first+a.size?j=!1:(f=b,i=ff(a,b))}function l(a){var b=(e?$g:_g)(i,g,c,!0);if(null==b){if(a||!k())return j=!1;g=e?(0>c?Sg:Rg)(i):0>c?i.text.length:0}else g=b;return!0}var f=b.line,g=b.ch,h=c,i=ff(a,f),j=!0;if("char"==d)l();else if("column"==d)l(!0);else if("word"==d||"group"==d)for(var m=null,n="group"==d,o=a.cm&&a.cm.getHelper(b,"wordChars"),p=!0;!(0>c)||l(!p);p=!1){var q=i.text.charAt(g)||"\n",r=lg(q,o)?"w":n&&"\n"==q?"n":!n||/\s/.test(q)?null:"p";if(!n||p||r||(r="s"),m&&m!=r){0>c&&(c=1,l());break}if(r&&(m=r),c>0&&!l(!p))break}var s=cb(a,oa(f,g),h,!0);return j||(s.hitSide=!0),s}function zd(a,b,c,d){var g,e=a.doc,f=b.left;if("page"==d){var h=Math.min(a.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight);g=b.top+c*(h-(0>c?1.5:.5)*Rb(a.display))}else"line"==d&&(g=c>0?b.bottom+3:b.top-3);for(;;){var i=Ob(a,f,g);if(!i.outside)break;if(0>c?0>=g:g>=e.height){i.hitSide=!0;break}g+=5*c}return i}function Cd(a,b,c,d){v.defaults[a]=b,c&&(Bd[a]=d?function(a,b,d){d!=Dd&&c(a,b,d)}:c)}function Nd(a){for(var c,d,e,f,b=a.split(/-(?!$)/),a=b[b.length-1],g=0;g<b.length-1;g++){var h=b[g];if(/^(cmd|meta|m)$/i.test(h))f=!0;else if(/^a(lt)?$/i.test(h))c=!0;else if(/^(c|ctrl|control)$/i.test(h))d=!0;else{if(!/^s(hift)$/i.test(h))throw new Error("Unrecognized modifier name: "+h);e=!0}}return c&&(a="Alt-"+a),d&&(a="Ctrl-"+a),f&&(a="Cmd-"+a),e&&(a="Shift-"+a),a}function Rd(a){return"string"==typeof a?Md[a]:a}function Vd(a,b,c,d,e){if(d&&d.shared)return Xd(a,b,c,d,e);if(a.cm&&!a.cm.curOp)return dc(a.cm,Vd)(a,b,c,d,e);var f=new Ud(a,e),g=pa(b,c);if(d&&hg(d,f,!1),g>0||0==g&&f.clearWhenEmpty!==!1)return f;if(f.replacedWith&&(f.collapsed=!0,f.widgetNode=pg("span",[f.replacedWith],"CodeMirror-widget"),d.handleMouseEvents||f.widgetNode.setAttribute("cm-ignore-events","true"),d.insertLeft&&(f.widgetNode.insertLeft=!0)),f.collapsed){if(re(a,b.line,b,c,f)||b.line!=c.line&&re(a,c.line,b,c,f))throw new Error("Inserting collapsed marker partially overlapping an existing one");u=!0}f.addToHistory&&sf(a,{from:b,to:c,origin:"markText"},a.sel,NaN);var j,h=b.line,i=a.cm;if(a.iter(h,c.line+1,function(a){i&&f.collapsed&&!i.options.lineWrapping&&se(a)==i.display.maxLine&&(j=!0),f.collapsed&&h!=b.line&&jf(a,0),ce(a,new _d(f,h==b.line?b.ch:null,h==c.line?c.ch:null)),++h}),f.collapsed&&a.iter(b.line,c.line+1,function(b){we(a,b)&&jf(b,0)}),f.clearOnEnter&&Jf(f,"beforeCursorEnter",function(){f.clear()}),f.readOnly&&(t=!0,(a.history.done.length||a.history.undone.length)&&a.clearHistory()),f.collapsed&&(f.id=++Td,f.atomic=!0),i){if(j&&(i.curOp.updateMaxLine=!0),f.collapsed)ic(i,b.line,c.line+1);else if(f.className||f.title||f.startStyle||f.endStyle||f.css)for(var k=b.line;k<=c.line;k++)jc(i,k,"text");f.atomic&&ab(i.doc),Nf(i,"markerAdded",i,f)}return f}function Xd(a,b,c,d,e){d=hg(d),d.shared=!1;var f=[Vd(a,b,c,d,e)],g=f[0],h=d.widgetNode;return df(a,function(a){h&&(d.widgetNode=h.cloneNode(!0)),f.push(Vd(a,Oa(a,b),Oa(a,c),d,e));for(var i=0;i<a.linked.length;++i)if(a.linked[i].isParent)return;g=bg(f)}),new Wd(f,g)}function Yd(a){return a.findMarks(oa(a.first,0),a.clipPos(oa(a.lastLine())),function(a){return a.parent})}function Zd(a,b){for(var c=0;c<b.length;c++){var d=b[c],e=d.find(),f=a.clipPos(e.from),g=a.clipPos(e.to);if(pa(f,g)){var h=Vd(a,f,g,d.primary,d.primary.type);d.markers.push(h),h.parent=d}}}function $d(a){for(var b=0;b<a.length;b++){var c=a[b],d=[c.primary.doc];df(c.primary.doc,function(a){d.push(a)});for(var e=0;e<c.markers.length;e++){var f=c.markers[e];-1==dg(d,f.doc)&&(f.parent=null,c.markers.splice(e--,1))}}}function _d(a,b,c){this.marker=a,this.from=b,this.to=c}function ae(a,b){if(a)for(var c=0;c<a.length;++c){var d=a[c];if(d.marker==b)return d}}function be(a,b){for(var c,d=0;d<a.length;++d)a[d]!=b&&(c||(c=[])).push(a[d]);return c}function ce(a,b){a.markedSpans=a.markedSpans?a.markedSpans.concat([b]):[b],b.marker.attachLine(a)}function de(a,b,c){if(a)for(var e,d=0;d<a.length;++d){var f=a[d],g=f.marker,h=null==f.from||(g.inclusiveLeft?f.from<=b:f.from<b);if(h||f.from==b&&"bookmark"==g.type&&(!c||!f.marker.insertLeft)){var i=null==f.to||(g.inclusiveRight?f.to>=b:f.to>b);(e||(e=[])).push(new _d(g,f.from,i?null:f.to))}}return e}function ee(a,b,c){if(a)for(var e,d=0;d<a.length;++d){var f=a[d],g=f.marker,h=null==f.to||(g.inclusiveRight?f.to>=b:f.to>b);if(h||f.from==b&&"bookmark"==g.type&&(!c||f.marker.insertLeft)){var i=null==f.from||(g.inclusiveLeft?f.from<=b:f.from<b);(e||(e=[])).push(new _d(g,i?null:f.from-b,null==f.to?null:f.to-b))}}return e}function fe(a,b){if(b.full)return null;var c=Qa(a,b.from.line)&&ff(a,b.from.line).markedSpans,d=Qa(a,b.to.line)&&ff(a,b.to.line).markedSpans;if(!c&&!d)return null;var e=b.from.ch,f=b.to.ch,g=0==pa(b.from,b.to),h=de(c,e,g),i=ee(d,f,g),j=1==b.text.length,k=bg(b.text).length+(j?e:0);if(h)for(var l=0;l<h.length;++l){var m=h[l];if(null==m.to){var n=ae(i,m.marker);n?j&&(m.to=null==n.to?null:n.to+k):m.to=e}}if(i)for(var l=0;l<i.length;++l){var m=i[l];if(null!=m.to&&(m.to+=k),null==m.from){var n=ae(h,m.marker);n||(m.from=k,j&&(h||(h=[])).push(m))}else m.from+=k,j&&(h||(h=[])).push(m)}h&&(h=ge(h)),i&&i!=h&&(i=ge(i));var o=[h];if(!j){var q,p=b.text.length-2;if(p>0&&h)for(var l=0;l<h.length;++l)null==h[l].to&&(q||(q=[])).push(new _d(h[l].marker,null,null));for(var l=0;p>l;++l)o.push(q);o.push(i)}return o}function ge(a){for(var b=0;b<a.length;++b){var c=a[b];null!=c.from&&c.from==c.to&&c.marker.clearWhenEmpty!==!1&&a.splice(b--,1)}return a.length?a:null}function he(a,b){var c=yf(a,b),d=fe(a,b);if(!c)return d;if(!d)return c;for(var e=0;e<c.length;++e){var f=c[e],g=d[e];if(f&&g)a:for(var h=0;h<g.length;++h){for(var i=g[h],j=0;j<f.length;++j)if(f[j].marker==i.marker)continue a;f.push(i)}else g&&(c[e]=g)}return c}function ie(a,b,c){var d=null;if(a.iter(b.line,c.line+1,function(a){if(a.markedSpans)for(var b=0;b<a.markedSpans.length;++b){var c=a.markedSpans[b].marker;!c.readOnly||d&&-1!=dg(d,c)||(d||(d=[])).push(c)}}),!d)return null;for(var e=[{from:b,to:c}],f=0;f<d.length;++f)for(var g=d[f],h=g.find(0),i=0;i<e.length;++i){var j=e[i];if(!(pa(j.to,h.from)<0||pa(j.from,h.to)>0)){var k=[i,1],l=pa(j.from,h.from),m=pa(j.to,h.to);(0>l||!g.inclusiveLeft&&!l)&&k.push({from:j.from,to:h.from}),(m>0||!g.inclusiveRight&&!m)&&k.push({from:h.to,to:j.to}),e.splice.apply(e,k),i+=k.length-1}}return e}function je(a){var b=a.markedSpans;if(b){for(var c=0;c<b.length;++c)b[c].marker.detachLine(a);a.markedSpans=null}}function ke(a,b){if(b){for(var c=0;c<b.length;++c)b[c].marker.attachLine(a);a.markedSpans=b}}function le(a){return a.inclusiveLeft?-1:0}function me(a){return a.inclusiveRight?1:0}function ne(a,b){var c=a.lines.length-b.lines.length;if(0!=c)return c;var d=a.find(),e=b.find(),f=pa(d.from,e.from)||le(a)-le(b);if(f)return-f;var g=pa(d.to,e.to)||me(a)-me(b);return g?g:b.id-a.id}function oe(a,b){var d,c=u&&a.markedSpans;if(c)for(var e,f=0;f<c.length;++f)e=c[f],e.marker.collapsed&&null==(b?e.from:e.to)&&(!d||ne(d,e.marker)<0)&&(d=e.marker);return d}function pe(a){return oe(a,!0)}function qe(a){return oe(a,!1)}function re(a,b,c,d,e){var f=ff(a,b),g=u&&f.markedSpans;if(g)for(var h=0;h<g.length;++h){var i=g[h];if(i.marker.collapsed){var j=i.marker.find(0),k=pa(j.from,c)||le(i.marker)-le(e),l=pa(j.to,d)||me(i.marker)-me(e);if(!(k>=0&&0>=l||0>=k&&l>=0)&&(0>=k&&(pa(j.to,c)>0||i.marker.inclusiveRight&&e.inclusiveLeft)||k>=0&&(pa(j.from,d)<0||i.marker.inclusiveLeft&&e.inclusiveRight)))return!0}}}function se(a){for(var b;b=pe(a);)a=b.find(-1,!0).line;return a}function te(a){for(var b,c;b=qe(a);)a=b.find(1,!0).line,(c||(c=[])).push(a);return c}function ue(a,b){var c=ff(a,b),d=se(c);return c==d?b:kf(d)}function ve(a,b){if(b>a.lastLine())return b;var d,c=ff(a,b);if(!we(a,c))return b;for(;d=qe(c);)c=d.find(1,!0).line;return kf(c)+1}function we(a,b){var c=u&&b.markedSpans;if(c)for(var d,e=0;e<c.length;++e)if(d=c[e],d.marker.collapsed){if(null==d.from)return!0;if(!d.marker.widgetNode&&0==d.from&&d.marker.inclusiveLeft&&xe(a,b,d))return!0}}function xe(a,b,c){if(null==c.to){var d=c.marker.find(1,!0);return xe(a,d.line,ae(d.line.markedSpans,c.marker))}if(c.marker.inclusiveRight&&c.to==b.text.length)return!0;for(var e,f=0;f<b.markedSpans.length;++f)if(e=b.markedSpans[f],e.marker.collapsed&&!e.marker.widgetNode&&e.from==c.to&&(null==e.to||e.to!=c.from)&&(e.marker.inclusiveLeft||c.marker.inclusiveRight)&&xe(a,b,e))return!0}function ze(a,b,c){mf(b)<(a.curOp&&a.curOp.scrollTop||a.doc.scrollTop)&&sd(a,null,c)}function Ae(a){if(null!=a.height)return a.height;var b=a.doc.cm;if(!b)return 0;if(!tg(document.body,a.node)){var c="position: relative;";a.coverGutter&&(c+="margin-left: -"+b.display.gutters.offsetWidth+"px;"),a.noHScroll&&(c+="width: "+b.display.wrapper.clientWidth+"px;"),sg(b.display.measure,pg("div",[a.node],null,c))}return a.height=a.node.offsetHeight}function Be(a,b,c,d){var e=new ye(a,c,d),f=a.cm;return f&&e.noHScroll&&(f.display.alignWidgets=!0),wd(a,b,"widget",function(b){var c=b.widgets||(b.widgets=[]);if(null==e.insertAt?c.push(e):c.splice(Math.min(c.length-1,Math.max(0,e.insertAt)),0,e),e.line=b,f&&!we(a,b)){var d=mf(b)<a.scrollTop;jf(b,b.height+Ae(e)),d&&sd(f,null,e.height),f.curOp.forceUpdate=!0}return!0}),e}function De(a,b,c,d){a.text=b,a.stateAfter&&(a.stateAfter=null),a.styles&&(a.styles=null),null!=a.order&&(a.order=null),je(a),ke(a,c);var e=d?d(a):1;e!=a.height&&jf(a,e)}function Ee(a){a.parent=null,je(a)}function Fe(a,b){if(a)for(;;){var c=a.match(/(?:^|\s+)line-(background-)?(\S+)/);if(!c)break;a=a.slice(0,c.index)+a.slice(c.index+c[0].length);var d=c[1]?"bgClass":"textClass";null==b[d]?b[d]=c[2]:new RegExp("(?:^|s)"+c[2]+"(?:$|s)").test(b[d])||(b[d]+=" "+c[2])}return a}function Ge(a,b){if(a.blankLine)return a.blankLine(b);if(a.innerMode){var c=v.innerMode(a,b);return c.mode.blankLine?c.mode.blankLine(c.state):void 0}}function He(a,b,c,d){for(var e=0;10>e;e++){d&&(d[0]=v.innerMode(a,c).mode);var f=a.token(b,c);if(b.pos>b.start)return f}throw new Error("Mode "+a.name+" failed to advance stream.")}function Ie(a,b,c,d){function e(a){return{start:k.start,end:k.pos,string:k.current(),type:h||null,state:a?Jd(f.mode,j):j}}var h,f=a.doc,g=f.mode;b=Oa(f,b);var l,i=ff(f,b.line),j=lb(a,b.line,c),k=new Sd(i.text,a.options.tabSize);for(d&&(l=[]);(d||k.pos<b.ch)&&!k.eol();)k.start=k.pos,h=He(g,k,j),d&&l.push(e(!0));return d?l:e()}function Je(a,b,c,d,e,f,g){var h=c.flattenSpans;null==h&&(h=a.options.flattenSpans);var l,i=0,j=null,k=new Sd(b,a.options.tabSize),m=a.options.addModeClass&&[null];for(""==b&&Fe(Ge(c,d),f);!k.eol();){if(k.pos>a.options.maxHighlightLength?(h=!1,g&&Me(a,b,d,k.pos),k.pos=b.length,l=null):l=Fe(He(c,k,d,m),f),m){var n=m[0].name;n&&(l="m-"+(l?n+" "+l:n))}if(!h||j!=l){for(;i<k.start;)i=Math.min(k.start,i+5e4),e(i,j);j=l}k.start=k.pos}for(;i<k.pos;){var o=Math.min(k.pos,i+5e4);e(o,j),i=o}}function Ke(a,b,c,d){var e=[a.state.modeGen],f={};Je(a,b.text,a.doc.mode,c,function(a,b){e.push(a,b)},f,d);for(var g=0;g<a.state.overlays.length;++g){var h=a.state.overlays[g],i=1,j=0;Je(a,b.text,h.mode,!0,function(a,b){for(var c=i;a>j;){var d=e[i];d>a&&e.splice(i,1,a,e[i+1],d),i+=2,j=Math.min(a,d)}if(b)if(h.opaque)e.splice(c,i-c,a,"cm-overlay "+b),i=c+2;else for(;i>c;c+=2){var f=e[c+1];e[c+1]=(f?f+" ":"")+"cm-overlay "+b}},f)}return{styles:e,classes:f.bgClass||f.textClass?f:null}}function Le(a,b,c){if(!b.styles||b.styles[0]!=a.state.modeGen){var d=lb(a,kf(b)),e=Ke(a,b,b.text.length>a.options.maxHighlightLength?Jd(a.doc.mode,d):d);b.stateAfter=d,b.styles=e.styles,e.classes?b.styleClasses=e.classes:b.styleClasses&&(b.styleClasses=null),c===a.doc.frontier&&a.doc.frontier++}return b.styles}function Me(a,b,c,d){var e=a.doc.mode,f=new Sd(b,a.options.tabSize);for(f.start=f.pos=d||0,""==b&&Ge(e,c);!f.eol();)He(e,f,c),f.start=f.pos}function Pe(a,b){if(!a||/^\s*$/.test(a))return null;var c=b.addModeClass?Oe:Ne;return c[a]||(c[a]=a.replace(/\S+/g,"cm-$&"))}function Qe(a,b){var c=pg("span",null,null,f?"padding-right: .1px":null),e={pre:pg("pre",[c],"CodeMirror-line"),content:c,col:0,pos:0,cm:a,splitSpaces:(d||f)&&a.getOption("lineWrapping")};b.measure={};for(var g=0;g<=(b.rest?b.rest.length:0);g++){var i,h=g?b.rest[g-1]:b.line;e.pos=0,e.addToken=Se,Hg(a.display.measure)&&(i=nf(h))&&(e.addToken=Ue(e.addToken,i)),e.map=[];var j=b!=a.display.externalMeasured&&kf(h);We(h,e,Le(a,h,j)),h.styleClasses&&(h.styleClasses.bgClass&&(e.bgClass=yg(h.styleClasses.bgClass,e.bgClass||"")),h.styleClasses.textClass&&(e.textClass=yg(h.styleClasses.textClass,e.textClass||""))),0==e.map.length&&e.map.push(0,0,e.content.appendChild(Fg(a.display.measure))),0==g?(b.measure.map=e.map,b.measure.cache={}):((b.measure.maps||(b.measure.maps=[])).push(e.map),(b.measure.caches||(b.measure.caches=[])).push({}))}return f&&/\bcm-tab\b/.test(e.content.lastChild.className)&&(e.content.className="cm-tab-wrap-hack"),Lf(a,"renderLine",a,b.line,e.pre),e.pre.className&&(e.textClass=yg(e.pre.className,e.textClass||"")),e}function Re(a){var b=pg("span","\u2022","cm-invalidchar");return b.title="\\u"+a.charCodeAt(0).toString(16),b.setAttribute("aria-label",b.title),b}function Se(a,b,c,f,g,h,i){if(b){var j=a.splitSpaces?b.replace(/ {3,}/g,Te):b,k=a.cm.state.specialChars,l=!1;if(k.test(b))for(var m=document.createDocumentFragment(),n=0;;){k.lastIndex=n;var o=k.exec(b),p=o?o.index-n:b.length-n;if(p){var q=document.createTextNode(j.slice(n,n+p));d&&9>e?m.appendChild(pg("span",[q])):m.appendChild(q),a.map.push(a.pos,a.pos+p,q),a.col+=p,a.pos+=p}if(!o)break;if(n+=p+1,"	"==o[0]){var r=a.cm.options.tabSize,s=r-a.col%r,q=m.appendChild(pg("span",ag(s),"cm-tab"));q.setAttribute("role","presentation"),q.setAttribute("cm-text","	"),a.col+=s}else if("\r"==o[0]||"\n"==o[0]){var q=m.appendChild(pg("span","\r"==o[0]?"\u240d":"\u2424","cm-invalidchar"));q.setAttribute("cm-text",o[0]),a.col+=1}else{var q=a.cm.options.specialCharPlaceholder(o[0]);q.setAttribute("cm-text",o[0]),d&&9>e?m.appendChild(pg("span",[q])):m.appendChild(q),a.col+=1}a.map.push(a.pos,a.pos+1,q),a.pos++}else{a.col+=b.length;var m=document.createTextNode(j);a.map.push(a.pos,a.pos+b.length,m),d&&9>e&&(l=!0),a.pos+=b.length}if(c||f||g||l||i){var t=c||"";f&&(t+=f),g&&(t+=g);var u=pg("span",[m],t,i);return h&&(u.title=h),a.content.appendChild(u)}a.content.appendChild(m)}}function Te(a){for(var b=" ",c=0;c<a.length-2;++c)b+=c%2?" ":"\xa0";return b+=" "}function Ue(a,b){return function(c,d,e,f,g,h,i){e=e?e+" cm-force-border":"cm-force-border";for(var j=c.pos,k=j+d.length;;){for(var l=0;l<b.length;l++){var m=b[l];if(m.to>j&&m.from<=j)break}if(m.to>=k)return a(c,d,e,f,g,h,i);a(c,d.slice(0,m.to-j),e,f,null,h,i),f=null,d=d.slice(m.to-j),j=m.to}}}function Ve(a,b,c,d){var e=!d&&c.widgetNode;e&&a.map.push(a.pos,a.pos+b,e),!d&&a.cm.display.input.needsContentAttribute&&(e||(e=a.content.appendChild(document.createElement("span"))),e.setAttribute("cm-marker",c.id)),e&&(a.cm.display.input.setUneditable(e),a.content.appendChild(e)),a.pos+=b}function We(a,b,c){var d=a.markedSpans,e=a.text,f=0;if(d)for(var k,l,n,o,p,q,r,h=e.length,i=0,g=1,j="",m=0;;){if(m==i){n=o=p=q=l="",r=null,m=1/0;for(var s=[],t=0;t<d.length;++t){var u=d[t],v=u.marker;"bookmark"==v.type&&u.from==i&&v.widgetNode?s.push(v):u.from<=i&&(null==u.to||u.to>i||v.collapsed&&u.to==i&&u.from==i)?(null!=u.to&&u.to!=i&&m>u.to&&(m=u.to,o=""),v.className&&(n+=" "+v.className),v.css&&(l=v.css),v.startStyle&&u.from==i&&(p+=" "+v.startStyle),v.endStyle&&u.to==m&&(o+=" "+v.endStyle),v.title&&!q&&(q=v.title),v.collapsed&&(!r||ne(r.marker,v)<0)&&(r=u)):u.from>i&&m>u.from&&(m=u.from)}if(r&&(r.from||0)==i){if(Ve(b,(null==r.to?h+1:r.to)-i,r.marker,null==r.from),null==r.to)return;r.to==i&&(r=!1)}if(!r&&s.length)for(var t=0;t<s.length;++t)Ve(b,0,s[t])}if(i>=h)break;for(var w=Math.min(h,m);;){if(j){var x=i+j.length;if(!r){var y=x>w?j.slice(0,w-i):j;b.addToken(b,y,k?k+n:n,p,i+y.length==m?o:"",q,l)}if(x>=w){j=j.slice(w-i),i=w;break}i=x,p=""}j=e.slice(f,f=c[g++]),k=Pe(c[g++],b.cm.options)}}else for(var g=1;g<c.length;g+=2)b.addToken(b,e.slice(f,f=c[g]),Pe(c[g+1],b.cm.options))}function Xe(a,b){return 0==b.from.ch&&0==b.to.ch&&""==bg(b.text)&&(!a.cm||a.cm.options.wholeLineUpdateBefore)}function Ye(a,b,c,d){function e(a){return c?c[a]:null}function f(a,c,e){De(a,c,e,d),Nf(a,"change",a,b)}function g(a,b){for(var c=a,f=[];b>c;++c)f.push(new Ce(j[c],e(c),d));return f}var h=b.from,i=b.to,j=b.text,k=ff(a,h.line),l=ff(a,i.line),m=bg(j),n=e(j.length-1),o=i.line-h.line;if(b.full)a.insert(0,g(0,j.length)),a.remove(j.length,a.size-j.length);else if(Xe(a,b)){var p=g(0,j.length-1);f(l,l.text,n),o&&a.remove(h.line,o),p.length&&a.insert(h.line,p)}else if(k==l)if(1==j.length)f(k,k.text.slice(0,h.ch)+m+k.text.slice(i.ch),n);else{var p=g(1,j.length-1);p.push(new Ce(m+k.text.slice(i.ch),n,d)),f(k,k.text.slice(0,h.ch)+j[0],e(0)),a.insert(h.line+1,p)}else if(1==j.length)f(k,k.text.slice(0,h.ch)+j[0]+l.text.slice(i.ch),e(0)),a.remove(h.line+1,o);else{f(k,k.text.slice(0,h.ch)+j[0],e(0)),f(l,m+l.text.slice(i.ch),n);var p=g(1,j.length-1);o>1&&a.remove(h.line+1,o-1),a.insert(h.line+1,p)}Nf(a,"change",a,b)}function Ze(a){this.lines=a,this.parent=null;for(var b=0,c=0;b<a.length;++b)a[b].parent=this,c+=a[b].height;this.height=c}function $e(a){this.children=a;for(var b=0,c=0,d=0;d<a.length;++d){var e=a[d];b+=e.chunkSize(),c+=e.height,e.parent=this}this.size=b,this.height=c,this.parent=null}function df(a,b,c){function d(a,e,f){if(a.linked)for(var g=0;g<a.linked.length;++g){var h=a.linked[g];if(h.doc!=e){var i=f&&h.sharedHist;(!c||i)&&(b(h.doc,i),d(h.doc,a,i))}}}d(a,null,!0)}function ef(a,b){if(b.cm)throw new Error("This document is already in use.");a.doc=b,b.cm=a,B(a),x(a),a.options.lineWrapping||H(a),a.options.mode=b.modeOption,ic(a)}function ff(a,b){if(b-=a.first,0>b||b>=a.size)throw new Error("There is no line "+(b+a.first)+" in the document.");for(var c=a;!c.lines;)for(var d=0;;++d){var e=c.children[d],f=e.chunkSize();if(f>b){c=e;break}b-=f}return c.lines[b]}function gf(a,b,c){var d=[],e=b.line;return a.iter(b.line,c.line+1,function(a){var f=a.text;e==c.line&&(f=f.slice(0,c.ch)),e==b.line&&(f=f.slice(b.ch)),d.push(f),++e}),d}function hf(a,b,c){var d=[];return a.iter(b,c,function(a){d.push(a.text)}),d}function jf(a,b){var c=b-a.height;if(c)for(var d=a;d;d=d.parent)d.height+=c}function kf(a){if(null==a.parent)return null;for(var b=a.parent,c=dg(b.lines,a),d=b.parent;d;b=d,d=d.parent)for(var e=0;d.children[e]!=b;++e)c+=d.children[e].chunkSize();return c+b.first}function lf(a,b){var c=a.first;a:do{for(var d=0;d<a.children.length;++d){var e=a.children[d],f=e.height;if(f>b){a=e;continue a}b-=f,c+=e.chunkSize()}return c}while(!a.lines);for(var d=0;d<a.lines.length;++d){var g=a.lines[d],h=g.height;if(h>b)break;b-=h}return c+d}function mf(a){a=se(a);for(var b=0,c=a.parent,d=0;d<c.lines.length;++d){var e=c.lines[d];if(e==a)break;b+=e.height}for(var f=c.parent;f;c=f,f=c.parent)for(var d=0;d<f.children.length;++d){var g=f.children[d];if(g==c)break;b+=g.height}return b}function nf(a){var b=a.order;return null==b&&(b=a.order=ah(a.text)),b}function of(a){this.done=[],this.undone=[],this.undoDepth=1/0,this.lastModTime=this.lastSelTime=0,this.lastOp=this.lastSelOp=null,this.lastOrigin=this.lastSelOrigin=null,this.generation=this.maxGeneration=a||1}function pf(a,b){var c={from:qa(b.from),to:bd(b),text:gf(a,b.from,b.to)};return wf(a,c,b.from.line,b.to.line+1),df(a,function(a){wf(a,c,b.from.line,b.to.line+1)},!0),c}function qf(a){for(;a.length;){var b=bg(a);if(!b.ranges)break;a.pop()}}function rf(a,b){return b?(qf(a.done),bg(a.done)):a.done.length&&!bg(a.done).ranges?bg(a.done):a.done.length>1&&!a.done[a.done.length-2].ranges?(a.done.pop(),bg(a.done)):void 0}function sf(a,b,c,d){var e=a.history;e.undone.length=0;var g,f=+new Date;if((e.lastOp==d||e.lastOrigin==b.origin&&b.origin&&("+"==b.origin.charAt(0)&&a.cm&&e.lastModTime>f-a.cm.options.historyEventDelay||"*"==b.origin.charAt(0)))&&(g=rf(e,e.lastOp==d))){var h=bg(g.changes);0==pa(b.from,b.to)&&0==pa(b.from,h.to)?h.to=bd(b):g.changes.push(pf(a,b))}else{var i=bg(e.done);for(i&&i.ranges||vf(a.sel,e.done),g={changes:[pf(a,b)],generation:e.generation},e.done.push(g);e.done.length>e.undoDepth;)e.done.shift(),e.done[0].ranges||e.done.shift()}e.done.push(c),e.generation=++e.maxGeneration,e.lastModTime=e.lastSelTime=f,e.lastOp=e.lastSelOp=d,e.lastOrigin=e.lastSelOrigin=b.origin,h||Lf(a,"historyAdded")}function tf(a,b,c,d){var e=b.charAt(0);return"*"==e||"+"==e&&c.ranges.length==d.ranges.length&&c.somethingSelected()==d.somethingSelected()&&new Date-a.history.lastSelTime<=(a.cm?a.cm.options.historyEventDelay:500)}function uf(a,b,c,d){var e=a.history,f=d&&d.origin;c==e.lastSelOp||f&&e.lastSelOrigin==f&&(e.lastModTime==e.lastSelTime&&e.lastOrigin==f||tf(a,f,bg(e.done),b))?e.done[e.done.length-1]=b:vf(b,e.done),e.lastSelTime=+new Date,e.lastSelOrigin=f,e.lastSelOp=c,d&&d.clearRedo!==!1&&qf(e.undone)}function vf(a,b){var c=bg(b);c&&c.ranges&&c.equals(a)||b.push(a)}function wf(a,b,c,d){var e=b["spans_"+a.id],f=0;a.iter(Math.max(a.first,c),Math.min(a.first+a.size,d),function(c){c.markedSpans&&((e||(e=b["spans_"+a.id]={}))[f]=c.markedSpans),++f})}function xf(a){if(!a)return null;for(var c,b=0;b<a.length;++b)a[b].marker.explicitlyCleared?c||(c=a.slice(0,b)):c&&c.push(a[b]);return c?c.length?c:null:a}function yf(a,b){var c=b["spans_"+a.id];if(!c)return null;for(var d=0,e=[];d<b.text.length;++d)e.push(xf(c[d]));return e}function zf(a,b,c){for(var d=0,e=[];d<a.length;++d){var f=a[d];if(f.ranges)e.push(c?Ja.prototype.deepCopy.call(f):f);else{var g=f.changes,h=[];e.push({changes:h});for(var i=0;i<g.length;++i){var k,j=g[i];if(h.push({from:j.from,to:j.to,text:j.text}),b)for(var l in j)(k=l.match(/^spans_(\d+)$/))&&dg(b,Number(k[1]))>-1&&(bg(h)[l]=j[l],delete j[l])}}}return e}function Af(a,b,c,d){c<a.line?a.line+=d:b<a.line&&(a.line=b,a.ch=0)}function Bf(a,b,c,d){for(var e=0;e<a.length;++e){var f=a[e],g=!0;if(f.ranges){f.copied||(f=a[e]=f.deepCopy(),f.copied=!0);for(var h=0;h<f.ranges.length;h++)Af(f.ranges[h].anchor,b,c,d),Af(f.ranges[h].head,b,c,d)}else{for(var h=0;h<f.changes.length;++h){var i=f.changes[h];if(c<i.from.line)i.from=oa(i.from.line+d,i.from.ch),i.to=oa(i.to.line+d,i.to.ch);else if(b<=i.to.line){g=!1;break}}g||(a.splice(0,e+1),e=0)}}}function Cf(a,b){var c=b.from.line,d=b.to.line,e=b.text.length-(d-c)-1;Bf(a.done,c,d,e),Bf(a.undone,c,d,e)}function Ff(a){return null!=a.defaultPrevented?a.defaultPrevented:0==a.returnValue}function Hf(a){return a.target||a.srcElement}function If(a){var b=a.which;return null==b&&(1&a.button?b=1:2&a.button?b=3:4&a.button&&(b=2)),o&&a.ctrlKey&&1==b&&(b=3),b}function Nf(a,b){function f(a){return function(){a.apply(null,d)}}var c=a._handlers&&a._handlers[b];if(c){var e,d=Array.prototype.slice.call(arguments,2);Tb?e=Tb.delayedCallbacks:Mf?e=Mf:(e=Mf=[],setTimeout(Of,0));for(var g=0;g<c.length;++g)e.push(f(c[g]))}}function Of(){var a=Mf;Mf=null;for(var b=0;b<a.length;++b)a[b]()}function Pf(a,b,c){return"string"==typeof b&&(b={type:b,preventDefault:function(){this.defaultPrevented=!0}}),Lf(a,c||b.type,a,b),Ff(b)||b.codemirrorIgnore}function Qf(a){var b=a._handlers&&a._handlers.cursorActivity;if(b)for(var c=a.curOp.cursorActivityHandlers||(a.curOp.cursorActivityHandlers=[]),d=0;d<b.length;++d)-1==dg(c,b[d])&&c.push(b[d])}function Rf(a,b){var c=a._handlers&&a._handlers[b];return c&&c.length>0}function Sf(a){a.prototype.on=function(a,b){Jf(this,a,b)},a.prototype.off=function(a,b){Kf(this,a,b)}}function Yf(){this.id=null}function ag(a){for(;_f.length<=a;)_f.push(bg(_f)+" ");return _f[a]}function bg(a){return a[a.length-1]}function dg(a,b){for(var c=0;c<a.length;++c)if(a[c]==b)return c;return-1}function eg(a,b){for(var c=[],d=0;d<a.length;d++)c[d]=b(a[d],d);return c}function fg(){}function gg(a,b){var c;return Object.create?c=Object.create(a):(fg.prototype=a,c=new fg),b&&hg(b,c),c}function hg(a,b,c){b||(b={});for(var d in a)!a.hasOwnProperty(d)||c===!1&&b.hasOwnProperty(d)||(b[d]=a[d]);return b}function ig(a){var b=Array.prototype.slice.call(arguments,1);return function(){return a.apply(null,b)}}function lg(a,b){return b?b.source.indexOf("\\w")>-1&&kg(a)?!0:b.test(a):kg(a)}function mg(a){for(var b in a)if(a.hasOwnProperty(b)&&a[b])return!1;return!0}function og(a){return a.charCodeAt(0)>=768&&ng.test(a)}function pg(a,b,c,d){var e=document.createElement(a);if(c&&(e.className=c),d&&(e.style.cssText=d),"string"==typeof b)e.appendChild(document.createTextNode(b));else if(b)for(var f=0;f<b.length;++f)e.appendChild(b[f]);return e}function rg(a){for(var b=a.childNodes.length;b>0;--b)a.removeChild(a.firstChild);return a}function sg(a,b){return rg(a).appendChild(b)}function ug(){for(var a=document.activeElement;a&&a.root&&a.root.activeElement;)a=a.root.activeElement;return a}function vg(a){return new RegExp("(^|\\s)"+a+"(?:$|\\s)\\s*")}function yg(a,b){for(var c=a.split(" "),d=0;d<c.length;d++)c[d]&&!vg(c[d]).test(b)&&(b+=" "+c[d]);return b}function zg(a){if(document.body.getElementsByClassName)for(var b=document.body.getElementsByClassName("CodeMirror"),c=0;c<b.length;c++){var d=b[c].CodeMirror;d&&a(d)}}function Bg(){Ag||(Cg(),Ag=!0)}function Cg(){var a;Jf(window,"resize",function(){null==a&&(a=setTimeout(function(){a=null,zg(rc)},100))}),Jf(window,"blur",function(){zg($c)})}function Fg(a){if(null==Eg){var b=pg("span","\u200b");sg(a,pg("span",[b,document.createTextNode("x")])),0!=a.firstChild.offsetHeight&&(Eg=b.offsetWidth<=1&&b.offsetHeight>2&&!(d&&8>e))}var c=Eg?pg("span","\u200b"):pg("span","\xa0",null,"display: inline-block; width: 1px; margin-right: -1px");return c.setAttribute("cm-text",""),c}function Hg(a){if(null!=Gg)return Gg;var b=sg(a,document.createTextNode("A\u062eA")),c=qg(b,0,1).getBoundingClientRect();if(!c||c.left==c.right)return!1;var d=qg(b,1,2).getBoundingClientRect();return Gg=d.right-c.right<3}function Mg(a){if(null!=Lg)return Lg;var b=sg(a,pg("span","x")),c=b.getBoundingClientRect(),d=qg(b,0,1).getBoundingClientRect();return Lg=Math.abs(c.left-d.left)>1}function Og(a,b,c,d){if(!a)return d(b,c,"ltr");for(var e=!1,f=0;f<a.length;++f){var g=a[f];(g.from<c&&g.to>b||b==c&&g.to==b)&&(d(Math.max(g.from,b),Math.min(g.to,c),1==g.level?"rtl":"ltr"),e=!0)}e||d(b,c,"ltr")}function Pg(a){return a.level%2?a.to:a.from}function Qg(a){return a.level%2?a.from:a.to}function Rg(a){var b=nf(a);return b?Pg(b[0]):0}function Sg(a){var b=nf(a);return b?Qg(bg(b)):a.text.length}function Tg(a,b){var c=ff(a.doc,b),d=se(c);d!=c&&(b=kf(d));var e=nf(d),f=e?e[0].level%2?Sg(d):Rg(d):0;return oa(b,f)}function Ug(a,b){for(var c,d=ff(a.doc,b);c=qe(d);)d=c.find(1,!0).line,b=null;var e=nf(d),f=e?e[0].level%2?Rg(d):Sg(d):d.text.length;return oa(null==b?kf(d):b,f)}function Vg(a,b){var c=Tg(a,b.line),d=ff(a.doc,c.line),e=nf(d);if(!e||0==e[0].level){var f=Math.max(0,d.text.search(/\S/)),g=b.line==c.line&&b.ch<=f&&b.ch;return oa(c.line,g?0:f)}return c}function Wg(a,b,c){var d=a[0].level;return b==d?!0:c==d?!1:c>b}function Yg(a,b){Xg=null;for(var d,c=0;c<a.length;++c){var e=a[c];if(e.from<b&&e.to>b)return c;if(e.from==b||e.to==b){if(null!=d)return Wg(a,e.level,a[d].level)?(e.from!=e.to&&(Xg=d),c):(e.from!=e.to&&(Xg=c),d);d=c}}return d}function Zg(a,b,c,d){if(!d)return b+c;do b+=c;while(b>0&&og(a.text.charAt(b)));return b}function $g(a,b,c,d){var e=nf(a);if(!e)return _g(a,b,c,d);for(var f=Yg(e,b),g=e[f],h=Zg(a,b,g.level%2?-c:c,d);;){if(h>g.from&&h<g.to)return h;if(h==g.from||h==g.to)return Yg(e,h)==f?h:(g=e[f+=c],c>0==g.level%2?g.to:g.from);if(g=e[f+=c],!g)return null;h=c>0==g.level%2?Zg(a,g.to,-1,d):Zg(a,g.from,1,d)}}function _g(a,b,c,d){var e=b+c;if(d)for(;e>0&&og(a.text.charAt(e));)e+=c;return 0>e||e>a.text.length?null:e}var a=/gecko\/\d/i.test(navigator.userAgent),b=/MSIE \d/.test(navigator.userAgent),c=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent),d=b||c,e=d&&(b?document.documentMode||6:c[1]),f=/WebKit\//.test(navigator.userAgent),g=f&&/Qt\/\d+\.\d+/.test(navigator.userAgent),h=/Chrome\//.test(navigator.userAgent),i=/Opera\//.test(navigator.userAgent),j=/Apple Computer/.test(navigator.vendor),k=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent),l=/PhantomJS/.test(navigator.userAgent),m=/AppleWebKit/.test(navigator.userAgent)&&/Mobile\/\w+/.test(navigator.userAgent),n=m||/Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent),o=m||/Mac/.test(navigator.platform),p=/win/i.test(navigator.platform),q=i&&navigator.userAgent.match(/Version\/(\d*\.\d*)/);q&&(q=Number(q[1])),q&&q>=15&&(i=!1,f=!0);var r=o&&(g||i&&(null==q||12.11>q)),s=a||d&&e>=9,t=!1,u=!1;K.prototype=hg({update:function(a){var b=a.scrollWidth>a.clientWidth+1,c=a.scrollHeight>a.clientHeight+1,d=a.nativeBarWidth;if(c){this.vert.style.display="block",this.vert.style.bottom=b?d+"px":"0";var e=a.viewHeight-(b?d:0);this.vert.firstChild.style.height=Math.max(0,a.scrollHeight-a.clientHeight+e)+"px"}else this.vert.style.display="",this.vert.firstChild.style.height="0";if(b){this.horiz.style.display="block",this.horiz.style.right=c?d+"px":"0",this.horiz.style.left=a.barLeft+"px";var f=a.viewWidth-a.barLeft-(c?d:0);this.horiz.firstChild.style.width=a.scrollWidth-a.clientWidth+f+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedOverlay&&a.clientHeight>0&&(0==d&&this.overlayHack(),this.checkedOverlay=!0),{right:c?d:0,bottom:b?d:0}},setScrollLeft:function(a){this.horiz.scrollLeft!=a&&(this.horiz.scrollLeft=a)},setScrollTop:function(a){this.vert.scrollTop!=a&&(this.vert.scrollTop=a)},overlayHack:function(){var a=o&&!k?"12px":"18px";this.horiz.style.minHeight=this.vert.style.minWidth=a;var b=this,c=function(a){Hf(a)!=b.vert&&Hf(a)!=b.horiz&&dc(b.cm,uc)(a)};Jf(this.vert,"mousedown",c),Jf(this.horiz,"mousedown",c)},clear:function(){var a=this.horiz.parentNode;a.removeChild(this.horiz),a.removeChild(this.vert)}},K.prototype),L.prototype=hg({update:function(){return{bottom:0,right:0}},setScrollLeft:function(){},setScrollTop:function(){},clear:function(){}},L.prototype),v.scrollbarModel={"native":K,"null":L},U.prototype.signal=function(a,b){Rf(a,b)&&this.events.push(arguments)},U.prototype.finish=function(){for(var a=0;a<this.events.length;a++)Lf.apply(null,this.events[a])};var oa=v.Pos=function(a,b){return this instanceof oa?(this.line=a,void(this.ch=b)):new oa(a,b)},pa=v.cmpPos=function(a,b){return a.line-b.line||a.ch-b.ch},va=null;Ba.prototype=hg({init:function(a){function h(a){if(c.somethingSelected())va=c.getSelections(),b.inaccurateSelection&&(b.prevInput="",b.inaccurateSelection=!1,g.value=va.join("\n"),cg(g));else{if(!c.options.lineWiseCopyCut)return;var d=za(c);va=d.text,"cut"==a.type?c.setSelections(d.ranges,null,Vf):(b.prevInput="",g.value=d.text.join("\n"),cg(g))}"cut"==a.type&&(c.state.cutIncoming=!0)}var b=this,c=this.cm,f=this.wrapper=Ca(),g=this.textarea=f.firstChild;a.wrapper.insertBefore(f,a.wrapper.firstChild),m&&(g.style.width="0px"),Jf(g,"input",function(){d&&e>=9&&b.hasSelection&&(b.hasSelection=null),b.poll()}),Jf(g,"paste",function(a){return xa(a,c)?!0:(c.state.pasteIncoming=!0,void b.fastPoll())}),Jf(g,"cut",h),Jf(g,"copy",h),Jf(a.scroller,"paste",function(d){sc(a,d)||(c.state.pasteIncoming=!0,b.focus())}),Jf(a.lineSpace,"selectstart",function(b){sc(a,b)||Df(b)}),Jf(g,"compositionstart",function(){var a=c.getCursor("from");b.composing={
+start:a,range:c.markText(a,c.getCursor("to"),{className:"CodeMirror-composing"})}}),Jf(g,"compositionend",function(){b.composing&&(b.poll(),b.composing.range.clear(),b.composing=null)})},prepareSelection:function(){var a=this.cm,b=a.display,c=a.doc,d=eb(a);if(a.options.moveInputWithCursor){var e=Lb(a,c.sel.primary().head,"div"),f=b.wrapper.getBoundingClientRect(),g=b.lineDiv.getBoundingClientRect();d.teTop=Math.max(0,Math.min(b.wrapper.clientHeight-10,e.top+g.top-f.top)),d.teLeft=Math.max(0,Math.min(b.wrapper.clientWidth-10,e.left+g.left-f.left))}return d},showSelection:function(a){var b=this.cm,c=b.display;sg(c.cursorDiv,a.cursors),sg(c.selectionDiv,a.selection),null!=a.teTop&&(this.wrapper.style.top=a.teTop+"px",this.wrapper.style.left=a.teLeft+"px")},reset:function(a){if(!this.contextMenuPending){var b,c,f=this.cm,g=f.doc;if(f.somethingSelected()){this.prevInput="";var h=g.sel.primary();b=Kg&&(h.to().line-h.from().line>100||(c=f.getSelection()).length>1e3);var i=b?"-":c||f.getSelection();this.textarea.value=i,f.state.focused&&cg(this.textarea),d&&e>=9&&(this.hasSelection=i)}else a||(this.prevInput=this.textarea.value="",d&&e>=9&&(this.hasSelection=null));this.inaccurateSelection=b}},getField:function(){return this.textarea},supportsTouch:function(){return!1},focus:function(){if("nocursor"!=this.cm.options.readOnly&&(!n||ug()!=this.textarea))try{this.textarea.focus()}catch(a){}},blur:function(){this.textarea.blur()},resetPosition:function(){this.wrapper.style.top=this.wrapper.style.left=0},receivedFocus:function(){this.slowPoll()},slowPoll:function(){var a=this;a.pollingFast||a.polling.set(this.cm.options.pollInterval,function(){a.poll(),a.cm.state.focused&&a.slowPoll()})},fastPoll:function(){function c(){var d=b.poll();d||a?(b.pollingFast=!1,b.slowPoll()):(a=!0,b.polling.set(60,c))}var a=!1,b=this;b.pollingFast=!0,b.polling.set(20,c)},poll:function(){var a=this.cm,b=this.textarea,c=this.prevInput;if(this.contextMenuPending||!a.state.focused||Jg(b)&&!c&&!this.composing||ua(a)||a.options.disableInput||a.state.keySeq)return!1;var f=b.value;if(f==c&&!a.somethingSelected())return!1;if(d&&e>=9&&this.hasSelection===f||o&&/[\uf700-\uf7ff]/.test(f))return a.display.input.reset(),!1;if(a.doc.sel==a.display.selForContextMenu){var g=f.charCodeAt(0);if(8203!=g||c||(c="\u200b"),8666==g)return this.reset(),this.cm.execCommand("undo")}for(var h=0,i=Math.min(c.length,f.length);i>h&&c.charCodeAt(h)==f.charCodeAt(h);)++h;var j=this;return cc(a,function(){wa(a,f.slice(h),c.length-h,null,j.composing?"*compose":null),f.length>1e3||f.indexOf("\n")>-1?b.value=j.prevInput="":j.prevInput=f,j.composing&&(j.composing.range.clear(),j.composing.range=a.markText(j.composing.start,a.getCursor("to"),{className:"CodeMirror-composing"}))}),!0},ensurePolled:function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},onKeyPress:function(){d&&e>=9&&(this.hasSelection=null),this.fastPoll()},onContextMenu:function(a){function o(){if(null!=h.selectionStart){var a=c.somethingSelected(),d="\u200b"+(a?h.value:"");h.value="\u21da",h.value=d,b.prevInput=a?"":"\u200b",h.selectionStart=1,h.selectionEnd=d.length,g.selForContextMenu=c.doc.sel}}function p(){if(b.contextMenuPending=!1,b.wrapper.style.position="relative",h.style.cssText=m,d&&9>e&&g.scrollbars.setScrollTop(g.scroller.scrollTop=k),null!=h.selectionStart){(!d||d&&9>e)&&o();var a=0,f=function(){g.selForContextMenu==c.doc.sel&&0==h.selectionStart&&h.selectionEnd>0&&"\u200b"==b.prevInput?dc(c,Ld.selectAll)(c):a++<10?g.detectingSelectAll=setTimeout(f,500):g.input.reset()};g.detectingSelectAll=setTimeout(f,200)}}var b=this,c=b.cm,g=c.display,h=b.textarea,j=tc(c,a),k=g.scroller.scrollTop;if(j&&!i){var l=c.options.resetSelectionOnContextMenu;l&&-1==c.doc.sel.contains(j)&&dc(c,Za)(c.doc,Ma(j),Vf);var m=h.style.cssText;if(b.wrapper.style.position="absolute",h.style.cssText="position: fixed; width: 30px; height: 30px; top: "+(a.clientY-5)+"px; left: "+(a.clientX-5)+"px; z-index: 1000; background: "+(d?"rgba(255, 255, 255, .05)":"transparent")+"; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);",f)var n=window.scrollY;if(g.input.focus(),f&&window.scrollTo(null,n),g.input.reset(),c.somethingSelected()||(h.value=b.prevInput=" "),b.contextMenuPending=!0,g.selForContextMenu=c.doc.sel,clearTimeout(g.detectingSelectAll),d&&e>=9&&o(),s){Gf(a);var q=function(){Kf(window,"mouseup",q),setTimeout(p,20)};Jf(window,"mouseup",q)}else setTimeout(p,50)}},setUneditable:fg,needsContentAttribute:!1},Ba.prototype),Da.prototype=hg({init:function(a){function e(a){if(c.somethingSelected())va=c.getSelections(),"cut"==a.type&&c.replaceSelection("",null,"cut");else{if(!c.options.lineWiseCopyCut)return;var b=za(c);va=b.text,"cut"==a.type&&c.operation(function(){c.setSelections(b.ranges,0,Vf),c.replaceSelection("",null,"cut")})}if(a.clipboardData&&!m)a.preventDefault(),a.clipboardData.clearData(),a.clipboardData.setData("text/plain",va.join("\n"));else{var d=Ca(),e=d.firstChild;c.display.lineSpace.insertBefore(d,c.display.lineSpace.firstChild),e.value=va.join("\n");var f=document.activeElement;cg(e),setTimeout(function(){c.display.lineSpace.removeChild(d),f.focus()},50)}}var b=this,c=b.cm,d=b.div=a.lineDiv;d.contentEditable="true",Aa(d),Jf(d,"paste",function(a){xa(a,c)}),Jf(d,"compositionstart",function(a){var d=a.data;if(b.composing={sel:c.doc.sel,data:d,startData:d},d){var e=c.doc.sel.primary(),f=c.getLine(e.head.line),g=f.indexOf(d,Math.max(0,e.head.ch-d.length));g>-1&&g<=e.head.ch&&(b.composing.sel=Ma(oa(e.head.line,g),oa(e.head.line,g+d.length)))}}),Jf(d,"compositionupdate",function(a){b.composing.data=a.data}),Jf(d,"compositionend",function(a){var c=b.composing;c&&(a.data==c.startData||/\u200b/.test(a.data)||(c.data=a.data),setTimeout(function(){c.handled||b.applyComposition(c),b.composing==c&&(b.composing=null)},50))}),Jf(d,"touchstart",function(){b.forceCompositionEnd()}),Jf(d,"input",function(){b.composing||b.pollContent()||cc(b.cm,function(){ic(c)})}),Jf(d,"copy",e),Jf(d,"cut",e)},prepareSelection:function(){var a=eb(this.cm,!1);return a.focus=this.cm.state.focused,a},showSelection:function(a){a&&this.cm.display.view.length&&(a.focus&&this.showPrimarySelection(),this.showMultipleSelections(a))},showPrimarySelection:function(){var b=window.getSelection(),c=this.cm.doc.sel.primary(),d=Ga(this.cm,b.anchorNode,b.anchorOffset),e=Ga(this.cm,b.focusNode,b.focusOffset);if(!d||d.bad||!e||e.bad||0!=pa(sa(d,e),c.from())||0!=pa(ra(d,e),c.to())){var f=Ea(this.cm,c.from()),g=Ea(this.cm,c.to());if(f||g){var h=this.cm.display.view,i=b.rangeCount&&b.getRangeAt(0);if(f){if(!g){var j=h[h.length-1].measure,k=j.maps?j.maps[j.maps.length-1]:j.map;g={node:k[k.length-1],offset:k[k.length-2]-k[k.length-3]}}}else f={node:h[0].measure.map[2],offset:0};try{var l=qg(f.node,f.offset,g.offset,g.node)}catch(m){}l&&(b.removeAllRanges(),b.addRange(l),i&&null==b.anchorNode?b.addRange(i):a&&this.startGracePeriod()),this.rememberSelection()}}},startGracePeriod:function(){var a=this;clearTimeout(this.gracePeriod),this.gracePeriod=setTimeout(function(){a.gracePeriod=!1,a.selectionChanged()&&a.cm.operation(function(){a.cm.curOp.selectionChanged=!0})},20)},showMultipleSelections:function(a){sg(this.cm.display.cursorDiv,a.cursors),sg(this.cm.display.selectionDiv,a.selection)},rememberSelection:function(){var a=window.getSelection();this.lastAnchorNode=a.anchorNode,this.lastAnchorOffset=a.anchorOffset,this.lastFocusNode=a.focusNode,this.lastFocusOffset=a.focusOffset},selectionInEditor:function(){var a=window.getSelection();if(!a.rangeCount)return!1;var b=a.getRangeAt(0).commonAncestorContainer;return tg(this.div,b)},focus:function(){"nocursor"!=this.cm.options.readOnly&&this.div.focus()},blur:function(){this.div.blur()},getField:function(){return this.div},supportsTouch:function(){return!0},receivedFocus:function(){function b(){a.cm.state.focused&&(a.pollSelection(),a.polling.set(a.cm.options.pollInterval,b))}var a=this;this.selectionInEditor()?this.pollSelection():cc(this.cm,function(){a.cm.curOp.selectionChanged=!0}),this.polling.set(this.cm.options.pollInterval,b)},selectionChanged:function(){var a=window.getSelection();return a.anchorNode!=this.lastAnchorNode||a.anchorOffset!=this.lastAnchorOffset||a.focusNode!=this.lastFocusNode||a.focusOffset!=this.lastFocusOffset},pollSelection:function(){if(!this.composing&&!this.gracePeriod&&this.selectionChanged()){var a=window.getSelection(),b=this.cm;this.rememberSelection();var c=Ga(b,a.anchorNode,a.anchorOffset),d=Ga(b,a.focusNode,a.focusOffset);c&&d&&cc(b,function(){Za(b.doc,Ma(c,d),Vf),(c.bad||d.bad)&&(b.curOp.selectionChanged=!0)})}},pollContent:function(){var a=this.cm,b=a.display,c=a.doc.sel.primary(),d=c.from(),e=c.to();if(d.line<b.viewFrom||e.line>b.viewTo-1)return!1;var f;if(d.line==b.viewFrom||0==(f=lc(a,d.line)))var g=kf(b.view[0].line),h=b.view[0].node;else var g=kf(b.view[f].line),h=b.view[f-1].node.nextSibling;var i=lc(a,e.line);if(i==b.view.length-1)var j=b.viewTo-1,k=b.lineDiv.lastChild;else var j=kf(b.view[i+1].line)-1,k=b.view[i+1].node.previousSibling;for(var l=a.doc.splitLines(Ia(a,h,k,g,j)),m=gf(a.doc,oa(g,0),oa(j,ff(a.doc,j).text.length));l.length>1&&m.length>1;)if(bg(l)==bg(m))l.pop(),m.pop(),j--;else{if(l[0]!=m[0])break;l.shift(),m.shift(),g++}for(var n=0,o=0,p=l[0],q=m[0],r=Math.min(p.length,q.length);r>n&&p.charCodeAt(n)==q.charCodeAt(n);)++n;for(var s=bg(l),t=bg(m),u=Math.min(s.length-(1==l.length?n:0),t.length-(1==m.length?n:0));u>o&&s.charCodeAt(s.length-o-1)==t.charCodeAt(t.length-o-1);)++o;l[l.length-1]=s.slice(0,s.length-o),l[0]=l[0].slice(n);var v=oa(g,n),w=oa(j,m.length?bg(m).length-o:0);return l.length>1||l[0]||pa(v,w)?(nd(a.doc,l,v,w,"+input"),!0):void 0},ensurePolled:function(){this.forceCompositionEnd()},reset:function(){this.forceCompositionEnd()},forceCompositionEnd:function(){this.composing&&!this.composing.handled&&(this.applyComposition(this.composing),this.composing.handled=!0,this.div.blur(),this.div.focus())},applyComposition:function(a){a.data&&a.data!=a.startData&&dc(this.cm,wa)(this.cm,a.data,0,a.sel)},setUneditable:function(a){a.setAttribute("contenteditable","false")},onKeyPress:function(a){a.preventDefault(),dc(this.cm,wa)(this.cm,String.fromCharCode(null==a.charCode?a.keyCode:a.charCode),0)},onContextMenu:fg,resetPosition:fg,needsContentAttribute:!0},Da.prototype),v.inputStyles={textarea:Ba,contenteditable:Da},Ja.prototype={primary:function(){return this.ranges[this.primIndex]},equals:function(a){if(a==this)return!0;if(a.primIndex!=this.primIndex||a.ranges.length!=this.ranges.length)return!1;for(var b=0;b<this.ranges.length;b++){var c=this.ranges[b],d=a.ranges[b];if(0!=pa(c.anchor,d.anchor)||0!=pa(c.head,d.head))return!1}return!0},deepCopy:function(){for(var a=[],b=0;b<this.ranges.length;b++)a[b]=new Ka(qa(this.ranges[b].anchor),qa(this.ranges[b].head));return new Ja(a,this.primIndex)},somethingSelected:function(){for(var a=0;a<this.ranges.length;a++)if(!this.ranges[a].empty())return!0;return!1},contains:function(a,b){b||(b=a);for(var c=0;c<this.ranges.length;c++){var d=this.ranges[c];if(pa(b,d.from())>=0&&pa(a,d.to())<=0)return c}return-1}},Ka.prototype={from:function(){return sa(this.anchor,this.head)},to:function(){return ra(this.anchor,this.head)},empty:function(){return this.head.line==this.anchor.line&&this.head.ch==this.anchor.ch}};var Qb,vc,wc,zb={left:0,right:0,top:0,bottom:0},Tb=null,Ub=0,Cc=0,Jc=0,Kc=null;d?Kc=-.53:a?Kc=15:h?Kc=-.7:j&&(Kc=-1/3);var Lc=function(a){var b=a.wheelDeltaX,c=a.wheelDeltaY;return null==b&&a.detail&&a.axis==a.HORIZONTAL_AXIS&&(b=a.detail),null==c&&a.detail&&a.axis==a.VERTICAL_AXIS?c=a.detail:null==c&&(c=a.wheelDelta),{x:b,y:c}};v.wheelEventPixels=function(a){var b=Lc(a);return b.x*=Kc,b.y*=Kc,b};var Pc=new Yf,Tc=null,bd=v.changeEnd=function(a){return a.text?oa(a.from.line+a.text.length-1,bg(a.text).length+(1==a.text.length?a.from.ch:0)):a.to};v.prototype={constructor:v,focus:function(){window.focus(),this.display.input.focus()},setOption:function(a,b){var c=this.options,d=c[a];(c[a]!=b||"mode"==a)&&(c[a]=b,Bd.hasOwnProperty(a)&&dc(this,Bd[a])(this,b,d))},getOption:function(a){return this.options[a]},getDoc:function(){return this.doc},addKeyMap:function(a,b){this.state.keyMaps[b?"push":"unshift"](Rd(a))},removeKeyMap:function(a){for(var b=this.state.keyMaps,c=0;c<b.length;++c)if(b[c]==a||b[c].name==a)return b.splice(c,1),!0},addOverlay:ec(function(a,b){var c=a.token?a:v.getMode(this.options,a);if(c.startState)throw new Error("Overlays may not be stateful.");this.state.overlays.push({mode:c,modeSpec:a,opaque:b&&b.opaque}),this.state.modeGen++,ic(this)}),removeOverlay:ec(function(a){for(var b=this.state.overlays,c=0;c<b.length;++c){var d=b[c].modeSpec;if(d==a||"string"==typeof a&&d.name==a)return b.splice(c,1),this.state.modeGen++,void ic(this)}}),indentLine:ec(function(a,b,c){"string"!=typeof b&&"number"!=typeof b&&(b=null==b?this.options.smartIndent?"smart":"prev":b?"add":"subtract"),Qa(this.doc,a)&&vd(this,a,b,c)}),indentSelection:ec(function(a){for(var b=this.doc.sel.ranges,c=-1,d=0;d<b.length;d++){var e=b[d];if(e.empty())e.head.line>c&&(vd(this,e.head.line,a,!0),c=e.head.line,d==this.doc.sel.primIndex&&td(this));else{var f=e.from(),g=e.to(),h=Math.max(c,f.line);c=Math.min(this.lastLine(),g.line-(g.ch?0:1))+1;for(var i=h;c>i;++i)vd(this,i,a);var j=this.doc.sel.ranges;0==f.ch&&b.length==j.length&&j[d].from().ch>0&&Va(this.doc,d,new Ka(f,j[d].to()),Vf)}}}),getTokenAt:function(a,b){return Ie(this,a,b)},getLineTokens:function(a,b){return Ie(this,oa(a),b,!0)},getTokenTypeAt:function(a){a=Oa(this.doc,a);var f,b=Le(this,ff(this.doc,a.line)),c=0,d=(b.length-1)/2,e=a.ch;if(0==e)f=b[2];else for(;;){var g=c+d>>1;if((g?b[2*g-1]:0)>=e)d=g;else{if(!(b[2*g+1]<e)){f=b[2*g+2];break}c=g+1}}var h=f?f.indexOf("cm-overlay "):-1;return 0>h?f:0==h?null:f.slice(0,h-1)},getModeAt:function(a){var b=this.doc.mode;return b.innerMode?v.innerMode(b,this.getTokenAt(a).state).mode:b},getHelper:function(a,b){return this.getHelpers(a,b)[0]},getHelpers:function(a,b){var c=[];if(!Id.hasOwnProperty(b))return c;var d=Id[b],e=this.getModeAt(a);if("string"==typeof e[b])d[e[b]]&&c.push(d[e[b]]);else if(e[b])for(var f=0;f<e[b].length;f++){var g=d[e[b][f]];g&&c.push(g)}else e.helperType&&d[e.helperType]?c.push(d[e.helperType]):d[e.name]&&c.push(d[e.name]);for(var f=0;f<d._global.length;f++){var h=d._global[f];h.pred(e,this)&&-1==dg(c,h.val)&&c.push(h.val)}return c},getStateAfter:function(a,b){var c=this.doc;return a=Na(c,null==a?c.first+c.size-1:a),lb(this,a+1,b)},cursorCoords:function(a,b){var c,d=this.doc.sel.primary();return c=null==a?d.head:"object"==typeof a?Oa(this.doc,a):a?d.from():d.to(),Lb(this,c,b||"page")},charCoords:function(a,b){return Kb(this,Oa(this.doc,a),b||"page")},coordsChar:function(a,b){return a=Jb(this,a,b||"page"),Ob(this,a.left,a.top)},lineAtHeight:function(a,b){return a=Jb(this,{top:a,left:0},b||"page").top,lf(this.doc,a+this.display.viewOffset)},heightAtLine:function(a,b){var d,c=!1;if("number"==typeof a){var e=this.doc.first+this.doc.size-1;a<this.doc.first?a=this.doc.first:a>e&&(a=e,c=!0),d=ff(this.doc,a)}else d=a;return Ib(this,d,{top:0,left:0},b||"page").top+(c?this.doc.height-mf(d):0)},defaultTextHeight:function(){return Rb(this.display)},defaultCharWidth:function(){return Sb(this.display)},setGutterMarker:ec(function(a,b,c){return wd(this.doc,a,"gutter",function(a){var d=a.gutterMarkers||(a.gutterMarkers={});return d[b]=c,!c&&mg(d)&&(a.gutterMarkers=null),!0})}),clearGutter:ec(function(a){var b=this,c=b.doc,d=c.first;c.iter(function(c){c.gutterMarkers&&c.gutterMarkers[a]&&(c.gutterMarkers[a]=null,jc(b,d,"gutter"),mg(c.gutterMarkers)&&(c.gutterMarkers=null)),++d})}),lineInfo:function(a){if("number"==typeof a){if(!Qa(this.doc,a))return null;var b=a;if(a=ff(this.doc,a),!a)return null}else{var b=kf(a);if(null==b)return null}return{line:b,handle:a,text:a.text,gutterMarkers:a.gutterMarkers,textClass:a.textClass,bgClass:a.bgClass,wrapClass:a.wrapClass,widgets:a.widgets}},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(a,b,c,d,e){var f=this.display;a=Lb(this,Oa(this.doc,a));var g=a.bottom,h=a.left;if(b.style.position="absolute",b.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(b),f.sizer.appendChild(b),"over"==d)g=a.top;else if("above"==d||"near"==d){var i=Math.max(f.wrapper.clientHeight,this.doc.height),j=Math.max(f.sizer.clientWidth,f.lineSpace.clientWidth);("above"==d||a.bottom+b.offsetHeight>i)&&a.top>b.offsetHeight?g=a.top-b.offsetHeight:a.bottom+b.offsetHeight<=i&&(g=a.bottom),h+b.offsetWidth>j&&(h=j-b.offsetWidth)}b.style.top=g+"px",b.style.left=b.style.right="","right"==e?(h=f.sizer.clientWidth-b.offsetWidth,b.style.right="0px"):("left"==e?h=0:"middle"==e&&(h=(f.sizer.clientWidth-b.offsetWidth)/2),b.style.left=h+"px"),c&&qd(this,h,g,h+b.offsetWidth,g+b.offsetHeight)},triggerOnKeyDown:ec(Uc),triggerOnKeyPress:ec(Xc),triggerOnKeyUp:Wc,execCommand:function(a){return Ld.hasOwnProperty(a)?Ld[a].call(null,this):void 0},triggerElectric:ec(function(a){ya(this,a)}),findPosH:function(a,b,c,d){var e=1;0>b&&(e=-1,b=-b);for(var f=0,g=Oa(this.doc,a);b>f&&(g=yd(this.doc,g,e,c,d),!g.hitSide);++f);return g},moveH:ec(function(a,b){var c=this;c.extendSelectionsBy(function(d){return c.display.shift||c.doc.extend||d.empty()?yd(c.doc,d.head,a,b,c.options.rtlMoveVisually):0>a?d.from():d.to()},Xf)}),deleteH:ec(function(a,b){var c=this.doc.sel,d=this.doc;c.somethingSelected()?d.replaceSelection("",null,"+delete"):xd(this,function(c){var e=yd(d,c.head,a,b,!1);return 0>a?{from:e,to:c.head}:{from:c.head,to:e}})}),findPosV:function(a,b,c,d){var e=1,f=d;0>b&&(e=-1,b=-b);for(var g=0,h=Oa(this.doc,a);b>g;++g){var i=Lb(this,h,"div");if(null==f?f=i.left:i.left=f,h=zd(this,i,e,c),h.hitSide)break}return h},moveV:ec(function(a,b){var c=this,d=this.doc,e=[],f=!c.display.shift&&!d.extend&&d.sel.somethingSelected();if(d.extendSelectionsBy(function(g){if(f)return 0>a?g.from():g.to();var h=Lb(c,g.head,"div");null!=g.goalColumn&&(h.left=g.goalColumn),e.push(h.left);var i=zd(c,h,a,b);return"page"==b&&g==d.sel.primary()&&sd(c,null,Kb(c,i,"div").top-h.top),i},Xf),e.length)for(var g=0;g<d.sel.ranges.length;g++)d.sel.ranges[g].goalColumn=e[g]}),findWordAt:function(a){var b=this.doc,c=ff(b,a.line).text,d=a.ch,e=a.ch;if(c){var f=this.getHelper(a,"wordChars");(a.xRel<0||e==c.length)&&d?--d:++e;for(var g=c.charAt(d),h=lg(g,f)?function(a){return lg(a,f)}:/\s/.test(g)?function(a){return/\s/.test(a)}:function(a){return!/\s/.test(a)&&!lg(a)};d>0&&h(c.charAt(d-1));)--d;for(;e<c.length&&h(c.charAt(e));)++e}return new Ka(oa(a.line,d),oa(a.line,e))},toggleOverwrite:function(a){(null==a||a!=this.state.overwrite)&&((this.state.overwrite=!this.state.overwrite)?xg(this.display.cursorDiv,"CodeMirror-overwrite"):wg(this.display.cursorDiv,"CodeMirror-overwrite"),Lf(this,"overwriteToggle",this,this.state.overwrite))},hasFocus:function(){return this.display.input.getField()==ug()},scrollTo:ec(function(a,b){(null!=a||null!=b)&&ud(this),null!=a&&(this.curOp.scrollLeft=a),null!=b&&(this.curOp.scrollTop=b)}),getScrollInfo:function(){var a=this.display.scroller;return{left:a.scrollLeft,top:a.scrollTop,height:a.scrollHeight-pb(this)-this.display.barHeight,width:a.scrollWidth-pb(this)-this.display.barWidth,clientHeight:rb(this),clientWidth:qb(this)}},scrollIntoView:ec(function(a,b){if(null==a?(a={from:this.doc.sel.primary().head,to:null},null==b&&(b=this.options.cursorScrollMargin)):"number"==typeof a?a={from:oa(a,0),to:null}:null==a.from&&(a={from:a,to:null}),a.to||(a.to=a.from),a.margin=b||0,null!=a.from.line)ud(this),this.curOp.scrollToPos=a;else{var c=rd(this,Math.min(a.from.left,a.to.left),Math.min(a.from.top,a.to.top)-a.margin,Math.max(a.from.right,a.to.right),Math.max(a.from.bottom,a.to.bottom)+a.margin);this.scrollTo(c.scrollLeft,c.scrollTop)}}),setSize:ec(function(a,b){function d(a){return"number"==typeof a||/^\d+$/.test(String(a))?a+"px":a}var c=this;null!=a&&(c.display.wrapper.style.width=d(a)),null!=b&&(c.display.wrapper.style.height=d(b)),c.options.lineWrapping&&Eb(this);var e=c.display.viewFrom;c.doc.iter(e,c.display.viewTo,function(a){if(a.widgets)for(var b=0;b<a.widgets.length;b++)if(a.widgets[b].noHScroll){jc(c,e,"widget");break}++e}),c.curOp.forceUpdate=!0,Lf(c,"refresh",this)}),operation:function(a){return cc(this,a)},refresh:ec(function(){var a=this.display.cachedTextHeight;ic(this),this.curOp.forceUpdate=!0,Fb(this),this.scrollTo(this.doc.scrollLeft,this.doc.scrollTop),F(this),(null==a||Math.abs(a-Rb(this.display))>.5)&&B(this),Lf(this,"refresh",this)}),swapDoc:ec(function(a){var b=this.doc;return b.cm=null,ef(this,a),Fb(this),this.display.input.reset(),this.scrollTo(a.scrollLeft,a.scrollTop),this.curOp.forceScroll=!0,Nf(this,"swapDoc",this,b),b}),getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},Sf(v);var Ad=v.defaults={},Bd=v.optionHandlers={},Dd=v.Init={toString:function(){return"CodeMirror.Init"}};Cd("value","",function(a,b){a.setValue(b)},!0),Cd("mode",null,function(a,b){a.doc.modeOption=b,x(a)},!0),Cd("indentUnit",2,x,!0),Cd("indentWithTabs",!1),Cd("smartIndent",!0),Cd("tabSize",4,function(a){y(a),Fb(a),ic(a)},!0),Cd("lineSeparator",null,function(a,b){if(a.doc.lineSep=b,b){var c=[],d=a.doc.first;a.doc.iter(function(a){for(var e=0;;){var f=a.text.indexOf(b,e);if(-1==f)break;e=f+b.length,c.push(oa(d,f))}d++});for(var e=c.length-1;e>=0;e--)nd(a.doc,b,c[e],oa(c[e].line,c[e].ch+b.length))}}),Cd("specialChars",/[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g,function(a,b,c){a.state.specialChars=new RegExp(b.source+(b.test("	")?"":"|	"),"g"),c!=v.Init&&a.refresh()}),Cd("specialCharPlaceholder",Re,function(a){a.refresh()},!0),Cd("electricChars",!0),Cd("inputStyle",n?"contenteditable":"textarea",function(){throw new Error("inputStyle can not (yet) be changed in a running editor")},!0),Cd("rtlMoveVisually",!p),Cd("wholeLineUpdateBefore",!0),Cd("theme","default",function(a){C(a),D(a)},!0),Cd("keyMap","default",function(a,b,c){var d=Rd(b),e=c!=v.Init&&Rd(c);e&&e.detach&&e.detach(a,d),d.attach&&d.attach(a,e||null)}),Cd("extraKeys",null),Cd("lineWrapping",!1,z,!0),Cd("gutters",[],function(a){I(a.options),D(a)},!0),Cd("fixedGutter",!0,function(a,b){a.display.gutters.style.left=b?T(a.display)+"px":"0",a.refresh()},!0),Cd("coverGutterNextToScrollbar",!1,function(a){N(a)},!0),Cd("scrollbarStyle","native",function(a){M(a),N(a),a.display.scrollbars.setScrollTop(a.doc.scrollTop),a.display.scrollbars.setScrollLeft(a.doc.scrollLeft)},!0),Cd("lineNumbers",!1,function(a){I(a.options),D(a)},!0),Cd("firstLineNumber",1,D,!0),Cd("lineNumberFormatter",function(a){return a},D,!0),Cd("showCursorWhenSelecting",!1,db,!0),Cd("resetSelectionOnContextMenu",!0),Cd("lineWiseCopyCut",!0),Cd("readOnly",!1,function(a,b){"nocursor"==b?($c(a),a.display.input.blur(),a.display.disabled=!0):(a.display.disabled=!1,b||a.display.input.reset())}),Cd("disableInput",!1,function(a,b){b||a.display.input.reset()},!0),Cd("dragDrop",!0,qc),Cd("cursorBlinkRate",530),Cd("cursorScrollMargin",0),Cd("cursorHeight",1,db,!0),Cd("singleCursorHeightPerLine",!0,db,!0),Cd("workTime",100),Cd("workDelay",100),Cd("flattenSpans",!0,y,!0),Cd("addModeClass",!1,y,!0),Cd("pollInterval",100),Cd("undoDepth",200,function(a,b){a.doc.history.undoDepth=b}),Cd("historyEventDelay",1250),Cd("viewportMargin",10,function(a){a.refresh()},!0),Cd("maxHighlightLength",1e4,y,!0),Cd("moveInputWithCursor",!0,function(a,b){b||a.display.input.resetPosition()}),Cd("tabindex",null,function(a,b){a.display.input.getField().tabIndex=b||""}),Cd("autofocus",null);var Ed=v.modes={},Fd=v.mimeModes={};v.defineMode=function(a,b){v.defaults.mode||"null"==a||(v.defaults.mode=a),arguments.length>2&&(b.dependencies=Array.prototype.slice.call(arguments,2)),Ed[a]=b},v.defineMIME=function(a,b){Fd[a]=b},v.resolveMode=function(a){if("string"==typeof a&&Fd.hasOwnProperty(a))a=Fd[a];else if(a&&"string"==typeof a.name&&Fd.hasOwnProperty(a.name)){var b=Fd[a.name];"string"==typeof b&&(b={name:b}),a=gg(b,a),a.name=b.name}else if("string"==typeof a&&/^[\w\-]+\/[\w\-]+\+xml$/.test(a))return v.resolveMode("application/xml");return"string"==typeof a?{name:a}:a||{name:"null"}},v.getMode=function(a,b){var b=v.resolveMode(b),c=Ed[b.name];if(!c)return v.getMode(a,"text/plain");var d=c(a,b);if(Gd.hasOwnProperty(b.name)){var e=Gd[b.name];for(var f in e)e.hasOwnProperty(f)&&(d.hasOwnProperty(f)&&(d["_"+f]=d[f]),d[f]=e[f])}if(d.name=b.name,b.helperType&&(d.helperType=b.helperType),b.modeProps)for(var f in b.modeProps)d[f]=b.modeProps[f];return d},v.defineMode("null",function(){return{token:function(a){a.skipToEnd()}}}),v.defineMIME("text/plain","null");var Gd=v.modeExtensions={};v.extendMode=function(a,b){var c=Gd.hasOwnProperty(a)?Gd[a]:Gd[a]={};hg(b,c)},v.defineExtension=function(a,b){v.prototype[a]=b},v.defineDocExtension=function(a,b){af.prototype[a]=b},v.defineOption=Cd;var Hd=[];v.defineInitHook=function(a){Hd.push(a)};var Id=v.helpers={};v.registerHelper=function(a,b,c){Id.hasOwnProperty(a)||(Id[a]=v[a]={_global:[]}),Id[a][b]=c},v.registerGlobalHelper=function(a,b,c,d){v.registerHelper(a,b,d),Id[a]._global.push({pred:c,val:d})};var Jd=v.copyState=function(a,b){if(b===!0)return b;if(a.copyState)return a.copyState(b);var c={};for(var d in b){var e=b[d];e instanceof Array&&(e=e.concat([])),c[d]=e}return c},Kd=v.startState=function(a,b,c){return a.startState?a.startState(b,c):!0};v.innerMode=function(a,b){for(;a.innerMode;){var c=a.innerMode(b);if(!c||c.mode==a)break;b=c.state,a=c.mode}return c||{mode:a,state:b}};var Ld=v.commands={selectAll:function(a){a.setSelection(oa(a.firstLine(),0),oa(a.lastLine()),Vf)},singleSelection:function(a){a.setSelection(a.getCursor("anchor"),a.getCursor("head"),Vf)},killLine:function(a){xd(a,function(b){if(b.empty()){var c=ff(a.doc,b.head.line).text.length;return b.head.ch==c&&b.head.line<a.lastLine()?{from:b.head,to:oa(b.head.line+1,0)}:{from:b.head,to:oa(b.head.line,c)}}return{from:b.from(),to:b.to()}})},deleteLine:function(a){xd(a,function(b){return{from:oa(b.from().line,0),to:Oa(a.doc,oa(b.to().line+1,0))}})},delLineLeft:function(a){xd(a,function(a){return{from:oa(a.from().line,0),to:a.from()}})},delWrappedLineLeft:function(a){xd(a,function(b){var c=a.charCoords(b.head,"div").top+5,d=a.coordsChar({left:0,top:c},"div");return{from:d,to:b.from()}})},delWrappedLineRight:function(a){xd(a,function(b){var c=a.charCoords(b.head,"div").top+5,d=a.coordsChar({left:a.display.lineDiv.offsetWidth+100,top:c},"div");return{from:b.from(),to:d}})},undo:function(a){a.undo()},redo:function(a){a.redo()},undoSelection:function(a){a.undoSelection()},redoSelection:function(a){a.redoSelection()},goDocStart:function(a){a.extendSelection(oa(a.firstLine(),0))},goDocEnd:function(a){a.extendSelection(oa(a.lastLine()))},goLineStart:function(a){a.extendSelectionsBy(function(b){return Tg(a,b.head.line)},{origin:"+move",bias:1})},goLineStartSmart:function(a){a.extendSelectionsBy(function(b){return Vg(a,b.head)},{origin:"+move",bias:1})},goLineEnd:function(a){a.extendSelectionsBy(function(b){return Ug(a,b.head.line)},{origin:"+move",bias:-1})},goLineRight:function(a){a.extendSelectionsBy(function(b){var c=a.charCoords(b.head,"div").top+5;return a.coordsChar({left:a.display.lineDiv.offsetWidth+100,top:c},"div")},Xf)},goLineLeft:function(a){a.extendSelectionsBy(function(b){var c=a.charCoords(b.head,"div").top+5;return a.coordsChar({left:0,top:c},"div")},Xf)},goLineLeftSmart:function(a){a.extendSelectionsBy(function(b){var c=a.charCoords(b.head,"div").top+5,d=a.coordsChar({left:0,top:c},"div");return d.ch<a.getLine(d.line).search(/\S/)?Vg(a,b.head):d},Xf)},goLineUp:function(a){a.moveV(-1,"line")},goLineDown:function(a){a.moveV(1,"line")},goPageUp:function(a){a.moveV(-1,"page")},goPageDown:function(a){a.moveV(1,"page")},goCharLeft:function(a){a.moveH(-1,"char")},goCharRight:function(a){a.moveH(1,"char")},goColumnLeft:function(a){a.moveH(-1,"column")},goColumnRight:function(a){a.moveH(1,"column")},goWordLeft:function(a){a.moveH(-1,"word")},goGroupRight:function(a){a.moveH(1,"group")},goGroupLeft:function(a){a.moveH(-1,"group")},goWordRight:function(a){a.moveH(1,"word")},delCharBefore:function(a){a.deleteH(-1,"char")},delCharAfter:function(a){a.deleteH(1,"char")},delWordBefore:function(a){a.deleteH(-1,"word")},delWordAfter:function(a){a.deleteH(1,"word")},delGroupBefore:function(a){a.deleteH(-1,"group")},delGroupAfter:function(a){a.deleteH(1,"group")},indentAuto:function(a){a.indentSelection("smart")},indentMore:function(a){a.indentSelection("add")},indentLess:function(a){a.indentSelection("subtract")},insertTab:function(a){a.replaceSelection("	")},insertSoftTab:function(a){for(var b=[],c=a.listSelections(),d=a.options.tabSize,e=0;e<c.length;e++){var f=c[e].from(),g=Zf(a.getLine(f.line),f.ch,d);b.push(new Array(d-g%d+1).join(" "))}a.replaceSelections(b)},defaultTab:function(a){a.somethingSelected()?a.indentSelection("add"):a.execCommand("insertTab")},transposeChars:function(a){cc(a,function(){for(var b=a.listSelections(),c=[],d=0;d<b.length;d++){var e=b[d].head,f=ff(a.doc,e.line).text;if(f)if(e.ch==f.length&&(e=new oa(e.line,e.ch-1)),e.ch>0)e=new oa(e.line,e.ch+1),a.replaceRange(f.charAt(e.ch-1)+f.charAt(e.ch-2),oa(e.line,e.ch-2),e,"+transpose");else if(e.line>a.doc.first){var g=ff(a.doc,e.line-1).text;g&&a.replaceRange(f.charAt(0)+a.doc.lineSeparator()+g.charAt(g.length-1),oa(e.line-1,g.length-1),oa(e.line,1),"+transpose")}c.push(new Ka(e,e))}a.setSelections(c)})},newlineAndIndent:function(a){cc(a,function(){for(var b=a.listSelections().length,c=0;b>c;c++){var d=a.listSelections()[c];a.replaceRange(a.doc.lineSeparator(),d.anchor,d.head,"+input"),a.indentLine(d.from().line+1,null,!0),td(a)}})},toggleOverwrite:function(a){a.toggleOverwrite()}},Md=v.keyMap={};Md.basic={Left:"goCharLeft",Right:"goCharRight",Up:"goLineUp",Down:"goLineDown",End:"goLineEnd",Home:"goLineStartSmart",PageUp:"goPageUp",PageDown:"goPageDown",Delete:"delCharAfter",Backspace:"delCharBefore","Shift-Backspace":"delCharBefore",Tab:"defaultTab","Shift-Tab":"indentAuto",Enter:"newlineAndIndent",Insert:"toggleOverwrite",Esc:"singleSelection"},Md.pcDefault={"Ctrl-A":"selectAll","Ctrl-D":"deleteLine","Ctrl-Z":"undo","Shift-Ctrl-Z":"redo","Ctrl-Y":"redo","Ctrl-Home":"goDocStart","Ctrl-End":"goDocEnd","Ctrl-Up":"goLineUp","Ctrl-Down":"goLineDown","Ctrl-Left":"goGroupLeft","Ctrl-Right":"goGroupRight","Alt-Left":"goLineStart","Alt-Right":"goLineEnd","Ctrl-Backspace":"delGroupBefore","Ctrl-Delete":"delGroupAfter","Ctrl-S":"save","Ctrl-F":"find","Ctrl-G":"findNext","Shift-Ctrl-G":"findPrev","Shift-Ctrl-F":"replace","Shift-Ctrl-R":"replaceAll","Ctrl-[":"indentLess","Ctrl-]":"indentMore","Ctrl-U":"undoSelection","Shift-Ctrl-U":"redoSelection","Alt-U":"redoSelection",fallthrough:"basic"},Md.emacsy={"Ctrl-F":"goCharRight","Ctrl-B":"goCharLeft","Ctrl-P":"goLineUp","Ctrl-N":"goLineDown","Alt-F":"goWordRight","Alt-B":"goWordLeft","Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd","Ctrl-V":"goPageDown","Shift-Ctrl-V":"goPageUp","Ctrl-D":"delCharAfter","Ctrl-H":"delCharBefore","Alt-D":"delWordAfter","Alt-Backspace":"delWordBefore","Ctrl-K":"killLine","Ctrl-T":"transposeChars"},Md.macDefault={"Cmd-A":"selectAll","Cmd-D":"deleteLine","Cmd-Z":"undo","Shift-Cmd-Z":"redo","Cmd-Y":"redo","Cmd-Home":"goDocStart","Cmd-Up":"goDocStart","Cmd-End":"goDocEnd","Cmd-Down":"goDocEnd","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight","Cmd-Left":"goLineLeft","Cmd-Right":"goLineRight","Alt-Backspace":"delGroupBefore","Ctrl-Alt-Backspace":"delGroupAfter","Alt-Delete":"delGroupAfter","Cmd-S":"save","Cmd-F":"find","Cmd-G":"findNext","Shift-Cmd-G":"findPrev","Cmd-Alt-F":"replace","Shift-Cmd-Alt-F":"replaceAll","Cmd-[":"indentLess","Cmd-]":"indentMore","Cmd-Backspace":"delWrappedLineLeft","Cmd-Delete":"delWrappedLineRight","Cmd-U":"undoSelection",
+"Shift-Cmd-U":"redoSelection","Ctrl-Up":"goDocStart","Ctrl-Down":"goDocEnd",fallthrough:["basic","emacsy"]},Md["default"]=o?Md.macDefault:Md.pcDefault,v.normalizeKeyMap=function(a){var b={};for(var c in a)if(a.hasOwnProperty(c)){var d=a[c];if(/^(name|fallthrough|(de|at)tach)$/.test(c))continue;if("..."==d){delete a[c];continue}for(var e=eg(c.split(" "),Nd),f=0;f<e.length;f++){var g,h;f==e.length-1?(h=e.join(" "),g=d):(h=e.slice(0,f+1).join(" "),g="...");var i=b[h];if(i){if(i!=g)throw new Error("Inconsistent bindings for "+h)}else b[h]=g}delete a[c]}for(var j in b)a[j]=b[j];return a};var Od=v.lookupKey=function(a,b,c,d){b=Rd(b);var e=b.call?b.call(a,d):b[a];if(e===!1)return"nothing";if("..."===e)return"multi";if(null!=e&&c(e))return"handled";if(b.fallthrough){if("[object Array]"!=Object.prototype.toString.call(b.fallthrough))return Od(a,b.fallthrough,c,d);for(var f=0;f<b.fallthrough.length;f++){var g=Od(a,b.fallthrough[f],c,d);if(g)return g}}},Pd=v.isModifierKey=function(a){var b="string"==typeof a?a:Ng[a.keyCode];return"Ctrl"==b||"Alt"==b||"Shift"==b||"Mod"==b},Qd=v.keyName=function(a,b){if(i&&34==a.keyCode&&a["char"])return!1;var c=Ng[a.keyCode],d=c;return null==d||a.altGraphKey?!1:(a.altKey&&"Alt"!=c&&(d="Alt-"+d),(r?a.metaKey:a.ctrlKey)&&"Ctrl"!=c&&(d="Ctrl-"+d),(r?a.ctrlKey:a.metaKey)&&"Cmd"!=c&&(d="Cmd-"+d),!b&&a.shiftKey&&"Shift"!=c&&(d="Shift-"+d),d)};v.fromTextArea=function(a,b){function d(){a.value=i.getValue()}if(b=b?hg(b):{},b.value=a.value,!b.tabindex&&a.tabIndex&&(b.tabindex=a.tabIndex),!b.placeholder&&a.placeholder&&(b.placeholder=a.placeholder),null==b.autofocus){var c=ug();b.autofocus=c==a||null!=a.getAttribute("autofocus")&&c==document.body}if(a.form&&(Jf(a.form,"submit",d),!b.leaveSubmitMethodAlone)){var e=a.form,f=e.submit;try{var g=e.submit=function(){d(),e.submit=f,e.submit(),e.submit=g}}catch(h){}}b.finishInit=function(b){b.save=d,b.getTextArea=function(){return a},b.toTextArea=function(){b.toTextArea=isNaN,d(),a.parentNode.removeChild(b.getWrapperElement()),a.style.display="",a.form&&(Kf(a.form,"submit",d),"function"==typeof a.form.submit&&(a.form.submit=f))}},a.style.display="none";var i=v(function(b){a.parentNode.insertBefore(b,a.nextSibling)},b);return i};var Sd=v.StringStream=function(a,b){this.pos=this.start=0,this.string=a,this.tabSize=b||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0};Sd.prototype={eol:function(){return this.pos>=this.string.length},sol:function(){return this.pos==this.lineStart},peek:function(){return this.string.charAt(this.pos)||void 0},next:function(){return this.pos<this.string.length?this.string.charAt(this.pos++):void 0},eat:function(a){var b=this.string.charAt(this.pos);if("string"==typeof a)var c=b==a;else var c=b&&(a.test?a.test(b):a(b));return c?(++this.pos,b):void 0},eatWhile:function(a){for(var b=this.pos;this.eat(a););return this.pos>b},eatSpace:function(){for(var a=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>a},skipToEnd:function(){this.pos=this.string.length},skipTo:function(a){var b=this.string.indexOf(a,this.pos);return b>-1?(this.pos=b,!0):void 0},backUp:function(a){this.pos-=a},column:function(){return this.lastColumnPos<this.start&&(this.lastColumnValue=Zf(this.string,this.start,this.tabSize,this.lastColumnPos,this.lastColumnValue),this.lastColumnPos=this.start),this.lastColumnValue-(this.lineStart?Zf(this.string,this.lineStart,this.tabSize):0)},indentation:function(){return Zf(this.string,null,this.tabSize)-(this.lineStart?Zf(this.string,this.lineStart,this.tabSize):0)},match:function(a,b,c){if("string"!=typeof a){var f=this.string.slice(this.pos).match(a);return f&&f.index>0?null:(f&&b!==!1&&(this.pos+=f[0].length),f)}var d=function(a){return c?a.toLowerCase():a},e=this.string.substr(this.pos,a.length);return d(e)==d(a)?(b!==!1&&(this.pos+=a.length),!0):void 0},current:function(){return this.string.slice(this.start,this.pos)},hideFirstChars:function(a,b){this.lineStart+=a;try{return b()}finally{this.lineStart-=a}}};var Td=0,Ud=v.TextMarker=function(a,b){this.lines=[],this.type=b,this.doc=a,this.id=++Td};Sf(Ud),Ud.prototype.clear=function(){if(!this.explicitlyCleared){var a=this.doc.cm,b=a&&!a.curOp;if(b&&Vb(a),Rf(this,"clear")){var c=this.find();c&&Nf(this,"clear",c.from,c.to)}for(var d=null,e=null,f=0;f<this.lines.length;++f){var g=this.lines[f],h=ae(g.markedSpans,this);a&&!this.collapsed?jc(a,kf(g),"text"):a&&(null!=h.to&&(e=kf(g)),null!=h.from&&(d=kf(g))),g.markedSpans=be(g.markedSpans,h),null==h.from&&this.collapsed&&!we(this.doc,g)&&a&&jf(g,Rb(a.display))}if(a&&this.collapsed&&!a.options.lineWrapping)for(var f=0;f<this.lines.length;++f){var i=se(this.lines[f]),j=G(i);j>a.display.maxLineLength&&(a.display.maxLine=i,a.display.maxLineLength=j,a.display.maxLineChanged=!0)}null!=d&&a&&this.collapsed&&ic(a,d,e+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,a&&ab(a.doc)),a&&Nf(a,"markerCleared",a,this),b&&Xb(a),this.parent&&this.parent.clear()}},Ud.prototype.find=function(a,b){null==a&&"bookmark"==this.type&&(a=1);for(var c,d,e=0;e<this.lines.length;++e){var f=this.lines[e],g=ae(f.markedSpans,this);if(null!=g.from&&(c=oa(b?f:kf(f),g.from),-1==a))return c;if(null!=g.to&&(d=oa(b?f:kf(f),g.to),1==a))return d}return c&&{from:c,to:d}},Ud.prototype.changed=function(){var a=this.find(-1,!0),b=this,c=this.doc.cm;a&&c&&cc(c,function(){var d=a.line,e=kf(a.line),f=wb(c,e);if(f&&(Db(f),c.curOp.selectionChanged=c.curOp.forceUpdate=!0),c.curOp.updateMaxLine=!0,!we(b.doc,d)&&null!=b.height){var g=b.height;b.height=null;var h=Ae(b)-g;h&&jf(d,d.height+h)}})},Ud.prototype.attachLine=function(a){if(!this.lines.length&&this.doc.cm){var b=this.doc.cm.curOp;b.maybeHiddenMarkers&&-1!=dg(b.maybeHiddenMarkers,this)||(b.maybeUnhiddenMarkers||(b.maybeUnhiddenMarkers=[])).push(this)}this.lines.push(a)},Ud.prototype.detachLine=function(a){if(this.lines.splice(dg(this.lines,a),1),!this.lines.length&&this.doc.cm){var b=this.doc.cm.curOp;(b.maybeHiddenMarkers||(b.maybeHiddenMarkers=[])).push(this)}};var Td=0,Wd=v.SharedTextMarker=function(a,b){this.markers=a,this.primary=b;for(var c=0;c<a.length;++c)a[c].parent=this};Sf(Wd),Wd.prototype.clear=function(){if(!this.explicitlyCleared){this.explicitlyCleared=!0;for(var a=0;a<this.markers.length;++a)this.markers[a].clear();Nf(this,"clear")}},Wd.prototype.find=function(a,b){return this.primary.find(a,b)};var ye=v.LineWidget=function(a,b,c){if(c)for(var d in c)c.hasOwnProperty(d)&&(this[d]=c[d]);this.doc=a,this.node=b};Sf(ye),ye.prototype.clear=function(){var a=this.doc.cm,b=this.line.widgets,c=this.line,d=kf(c);if(null!=d&&b){for(var e=0;e<b.length;++e)b[e]==this&&b.splice(e--,1);b.length||(c.widgets=null);var f=Ae(this);jf(c,Math.max(0,c.height-f)),a&&cc(a,function(){ze(a,c,-f),jc(a,d,"widget")})}},ye.prototype.changed=function(){var a=this.height,b=this.doc.cm,c=this.line;this.height=null;var d=Ae(this)-a;d&&(jf(c,c.height+d),b&&cc(b,function(){b.curOp.forceUpdate=!0,ze(b,c,d)}))};var Ce=v.Line=function(a,b,c){this.text=a,ke(this,b),this.height=c?c(this):1};Sf(Ce),Ce.prototype.lineNo=function(){return kf(this)};var Ne={},Oe={};Ze.prototype={chunkSize:function(){return this.lines.length},removeInner:function(a,b){for(var c=a,d=a+b;d>c;++c){var e=this.lines[c];this.height-=e.height,Ee(e),Nf(e,"delete")}this.lines.splice(a,b)},collapse:function(a){a.push.apply(a,this.lines)},insertInner:function(a,b,c){this.height+=c,this.lines=this.lines.slice(0,a).concat(b).concat(this.lines.slice(a));for(var d=0;d<b.length;++d)b[d].parent=this},iterN:function(a,b,c){for(var d=a+b;d>a;++a)if(c(this.lines[a]))return!0}},$e.prototype={chunkSize:function(){return this.size},removeInner:function(a,b){this.size-=b;for(var c=0;c<this.children.length;++c){var d=this.children[c],e=d.chunkSize();if(e>a){var f=Math.min(b,e-a),g=d.height;if(d.removeInner(a,f),this.height-=g-d.height,e==f&&(this.children.splice(c--,1),d.parent=null),0==(b-=f))break;a=0}else a-=e}if(this.size-b<25&&(this.children.length>1||!(this.children[0]instanceof Ze))){var h=[];this.collapse(h),this.children=[new Ze(h)],this.children[0].parent=this}},collapse:function(a){for(var b=0;b<this.children.length;++b)this.children[b].collapse(a)},insertInner:function(a,b,c){this.size+=b.length,this.height+=c;for(var d=0;d<this.children.length;++d){var e=this.children[d],f=e.chunkSize();if(f>=a){if(e.insertInner(a,b,c),e.lines&&e.lines.length>50){for(;e.lines.length>50;){var g=e.lines.splice(e.lines.length-25,25),h=new Ze(g);e.height-=h.height,this.children.splice(d+1,0,h),h.parent=this}this.maybeSpill()}break}a-=f}},maybeSpill:function(){if(!(this.children.length<=10)){var a=this;do{var b=a.children.splice(a.children.length-5,5),c=new $e(b);if(a.parent){a.size-=c.size,a.height-=c.height;var e=dg(a.parent.children,a);a.parent.children.splice(e+1,0,c)}else{var d=new $e(a.children);d.parent=a,a.children=[d,c],a=d}c.parent=a.parent}while(a.children.length>10);a.parent.maybeSpill()}},iterN:function(a,b,c){for(var d=0;d<this.children.length;++d){var e=this.children[d],f=e.chunkSize();if(f>a){var g=Math.min(b,f-a);if(e.iterN(a,g,c))return!0;if(0==(b-=g))break;a=0}else a-=f}}};var _e=0,af=v.Doc=function(a,b,c,d){if(!(this instanceof af))return new af(a,b,c,d);null==c&&(c=0),$e.call(this,[new Ze([new Ce("",null)])]),this.first=c,this.scrollTop=this.scrollLeft=0,this.cantEdit=!1,this.cleanGeneration=1,this.frontier=c;var e=oa(c,0);this.sel=Ma(e),this.history=new of(null),this.id=++_e,this.modeOption=b,this.lineSep=d,"string"==typeof a&&(a=this.splitLines(a)),Ye(this,{from:e,to:e,text:a}),Za(this,Ma(e),Vf)};af.prototype=gg($e.prototype,{constructor:af,iter:function(a,b,c){c?this.iterN(a-this.first,b-a,c):this.iterN(this.first,this.first+this.size,a)},insert:function(a,b){for(var c=0,d=0;d<b.length;++d)c+=b[d].height;this.insertInner(a-this.first,b,c)},remove:function(a,b){this.removeInner(a-this.first,b)},getValue:function(a){var b=hf(this,this.first,this.first+this.size);return a===!1?b:b.join(a||this.lineSeparator())},setValue:fc(function(a){var b=oa(this.first,0),c=this.first+this.size-1;hd(this,{from:b,to:oa(c,ff(this,c).text.length),text:this.splitLines(a),origin:"setValue",full:!0},!0),Za(this,Ma(b))}),replaceRange:function(a,b,c,d){b=Oa(this,b),c=c?Oa(this,c):b,nd(this,a,b,c,d)},getRange:function(a,b,c){var d=gf(this,Oa(this,a),Oa(this,b));return c===!1?d:d.join(c||this.lineSeparator())},getLine:function(a){var b=this.getLineHandle(a);return b&&b.text},getLineHandle:function(a){return Qa(this,a)?ff(this,a):void 0},getLineNumber:function(a){return kf(a)},getLineHandleVisualStart:function(a){return"number"==typeof a&&(a=ff(this,a)),se(a)},lineCount:function(){return this.size},firstLine:function(){return this.first},lastLine:function(){return this.first+this.size-1},clipPos:function(a){return Oa(this,a)},getCursor:function(a){var c,b=this.sel.primary();return c=null==a||"head"==a?b.head:"anchor"==a?b.anchor:"end"==a||"to"==a||a===!1?b.to():b.from()},listSelections:function(){return this.sel.ranges},somethingSelected:function(){return this.sel.somethingSelected()},setCursor:fc(function(a,b,c){Wa(this,Oa(this,"number"==typeof a?oa(a,b||0):a),null,c)}),setSelection:fc(function(a,b,c){Wa(this,Oa(this,a),Oa(this,b||a),c)}),extendSelection:fc(function(a,b,c){Ta(this,Oa(this,a),b&&Oa(this,b),c)}),extendSelections:fc(function(a,b){Ua(this,Ra(this,a,b))}),extendSelectionsBy:fc(function(a,b){Ua(this,eg(this.sel.ranges,a),b)}),setSelections:fc(function(a,b,c){if(a.length){for(var d=0,e=[];d<a.length;d++)e[d]=new Ka(Oa(this,a[d].anchor),Oa(this,a[d].head));null==b&&(b=Math.min(a.length-1,this.sel.primIndex)),Za(this,La(e,b),c)}}),addSelection:fc(function(a,b,c){var d=this.sel.ranges.slice(0);d.push(new Ka(Oa(this,a),Oa(this,b||a))),Za(this,La(d,d.length-1),c)}),getSelection:function(a){for(var c,b=this.sel.ranges,d=0;d<b.length;d++){var e=gf(this,b[d].from(),b[d].to());c=c?c.concat(e):e}return a===!1?c:c.join(a||this.lineSeparator())},getSelections:function(a){for(var b=[],c=this.sel.ranges,d=0;d<c.length;d++){var e=gf(this,c[d].from(),c[d].to());a!==!1&&(e=e.join(a||this.lineSeparator())),b[d]=e}return b},replaceSelection:function(a,b,c){for(var d=[],e=0;e<this.sel.ranges.length;e++)d[e]=a;this.replaceSelections(d,b,c||"+input")},replaceSelections:fc(function(a,b,c){for(var d=[],e=this.sel,f=0;f<e.ranges.length;f++){var g=e.ranges[f];d[f]={from:g.from(),to:g.to(),text:this.splitLines(a[f]),origin:c}}for(var h=b&&"end"!=b&&fd(this,d,b),f=d.length-1;f>=0;f--)hd(this,d[f]);h?Ya(this,h):this.cm&&td(this.cm)}),undo:fc(function(){jd(this,"undo")}),redo:fc(function(){jd(this,"redo")}),undoSelection:fc(function(){jd(this,"undo",!0)}),redoSelection:fc(function(){jd(this,"redo",!0)}),setExtending:function(a){this.extend=a},getExtending:function(){return this.extend},historySize:function(){for(var a=this.history,b=0,c=0,d=0;d<a.done.length;d++)a.done[d].ranges||++b;for(var d=0;d<a.undone.length;d++)a.undone[d].ranges||++c;return{undo:b,redo:c}},clearHistory:function(){this.history=new of(this.history.maxGeneration)},markClean:function(){this.cleanGeneration=this.changeGeneration(!0)},changeGeneration:function(a){return a&&(this.history.lastOp=this.history.lastSelOp=this.history.lastOrigin=null),this.history.generation},isClean:function(a){return this.history.generation==(a||this.cleanGeneration)},getHistory:function(){return{done:zf(this.history.done),undone:zf(this.history.undone)}},setHistory:function(a){var b=this.history=new of(this.history.maxGeneration);b.done=zf(a.done.slice(0),null,!0),b.undone=zf(a.undone.slice(0),null,!0)},addLineClass:fc(function(a,b,c){return wd(this,a,"gutter"==b?"gutter":"class",function(a){var d="text"==b?"textClass":"background"==b?"bgClass":"gutter"==b?"gutterClass":"wrapClass";if(a[d]){if(vg(c).test(a[d]))return!1;a[d]+=" "+c}else a[d]=c;return!0})}),removeLineClass:fc(function(a,b,c){return wd(this,a,"gutter"==b?"gutter":"class",function(a){var d="text"==b?"textClass":"background"==b?"bgClass":"gutter"==b?"gutterClass":"wrapClass",e=a[d];if(!e)return!1;if(null==c)a[d]=null;else{var f=e.match(vg(c));if(!f)return!1;var g=f.index+f[0].length;a[d]=e.slice(0,f.index)+(f.index&&g!=e.length?" ":"")+e.slice(g)||null}return!0})}),addLineWidget:fc(function(a,b,c){return Be(this,a,b,c)}),removeLineWidget:function(a){a.clear()},markText:function(a,b,c){return Vd(this,Oa(this,a),Oa(this,b),c,"range")},setBookmark:function(a,b){var c={replacedWith:b&&(null==b.nodeType?b.widget:b),insertLeft:b&&b.insertLeft,clearWhenEmpty:!1,shared:b&&b.shared,handleMouseEvents:b&&b.handleMouseEvents};return a=Oa(this,a),Vd(this,a,a,c,"bookmark")},findMarksAt:function(a){a=Oa(this,a);var b=[],c=ff(this,a.line).markedSpans;if(c)for(var d=0;d<c.length;++d){var e=c[d];(null==e.from||e.from<=a.ch)&&(null==e.to||e.to>=a.ch)&&b.push(e.marker.parent||e.marker)}return b},findMarks:function(a,b,c){a=Oa(this,a),b=Oa(this,b);var d=[],e=a.line;return this.iter(a.line,b.line+1,function(f){var g=f.markedSpans;if(g)for(var h=0;h<g.length;h++){var i=g[h];e==a.line&&a.ch>i.to||null==i.from&&e!=a.line||e==b.line&&i.from>b.ch||c&&!c(i.marker)||d.push(i.marker.parent||i.marker)}++e}),d},getAllMarks:function(){var a=[];return this.iter(function(b){var c=b.markedSpans;if(c)for(var d=0;d<c.length;++d)null!=c[d].from&&a.push(c[d].marker)}),a},posFromIndex:function(a){var b,c=this.first;return this.iter(function(d){var e=d.text.length+1;return e>a?(b=a,!0):(a-=e,void++c)}),Oa(this,oa(c,b))},indexFromPos:function(a){a=Oa(this,a);var b=a.ch;return a.line<this.first||a.ch<0?0:(this.iter(this.first,a.line,function(a){b+=a.text.length+1}),b)},copy:function(a){var b=new af(hf(this,this.first,this.first+this.size),this.modeOption,this.first,this.lineSep);return b.scrollTop=this.scrollTop,b.scrollLeft=this.scrollLeft,b.sel=this.sel,b.extend=!1,a&&(b.history.undoDepth=this.history.undoDepth,b.setHistory(this.getHistory())),b},linkedDoc:function(a){a||(a={});var b=this.first,c=this.first+this.size;null!=a.from&&a.from>b&&(b=a.from),null!=a.to&&a.to<c&&(c=a.to);var d=new af(hf(this,b,c),a.mode||this.modeOption,b,this.lineSep);return a.sharedHist&&(d.history=this.history),(this.linked||(this.linked=[])).push({doc:d,sharedHist:a.sharedHist}),d.linked=[{doc:this,isParent:!0,sharedHist:a.sharedHist}],Zd(d,Yd(this)),d},unlinkDoc:function(a){if(a instanceof v&&(a=a.doc),this.linked)for(var b=0;b<this.linked.length;++b){var c=this.linked[b];if(c.doc==a){this.linked.splice(b,1),a.unlinkDoc(this),$d(Yd(this));break}}if(a.history==this.history){var d=[a.id];df(a,function(a){d.push(a.id)},!0),a.history=new of(null),a.history.done=zf(this.history.done,d),a.history.undone=zf(this.history.undone,d)}},iterLinkedDocs:function(a){df(this,a)},getMode:function(){return this.mode},getEditor:function(){return this.cm},splitLines:function(a){return this.lineSep?a.split(this.lineSep):Ig(a)},lineSeparator:function(){return this.lineSep||"\n"}}),af.prototype.eachLine=af.prototype.iter;var bf="iter insert remove copy getEditor constructor".split(" ");for(var cf in af.prototype)af.prototype.hasOwnProperty(cf)&&dg(bf,cf)<0&&(v.prototype[cf]=function(a){return function(){return a.apply(this.doc,arguments)}}(af.prototype[cf]));Sf(af);var Df=v.e_preventDefault=function(a){a.preventDefault?a.preventDefault():a.returnValue=!1},Ef=v.e_stopPropagation=function(a){a.stopPropagation?a.stopPropagation():a.cancelBubble=!0},Gf=v.e_stop=function(a){Df(a),Ef(a)},Jf=v.on=function(a,b,c){if(a.addEventListener)a.addEventListener(b,c,!1);else if(a.attachEvent)a.attachEvent("on"+b,c);else{var d=a._handlers||(a._handlers={}),e=d[b]||(d[b]=[]);e.push(c)}},Kf=v.off=function(a,b,c){if(a.removeEventListener)a.removeEventListener(b,c,!1);else if(a.detachEvent)a.detachEvent("on"+b,c);else{var d=a._handlers&&a._handlers[b];if(!d)return;for(var e=0;e<d.length;++e)if(d[e]==c){d.splice(e,1);break}}},Lf=v.signal=function(a,b){var c=a._handlers&&a._handlers[b];if(c)for(var d=Array.prototype.slice.call(arguments,2),e=0;e<c.length;++e)c[e].apply(null,d)},Mf=null,Tf=30,Uf=v.Pass={toString:function(){return"CodeMirror.Pass"}},Vf={scroll:!1},Wf={origin:"*mouse"},Xf={origin:"+move"};Yf.prototype.set=function(a,b){clearTimeout(this.id),this.id=setTimeout(b,a)};var Zf=v.countColumn=function(a,b,c,d,e){null==b&&(b=a.search(/[^\s\u00a0]/),-1==b&&(b=a.length));for(var f=d||0,g=e||0;;){var h=a.indexOf("	",f);if(0>h||h>=b)return g+(b-f);g+=h-f,g+=c-g%c,f=h+1}},$f=v.findColumn=function(a,b,c){for(var d=0,e=0;;){var f=a.indexOf("	",d);-1==f&&(f=a.length);var g=f-d;if(f==a.length||e+g>=b)return d+Math.min(g,b-e);if(e+=f-d,e+=c-e%c,d=f+1,e>=b)return d}},_f=[""],cg=function(a){a.select()};m?cg=function(a){a.selectionStart=0,a.selectionEnd=a.value.length}:d&&(cg=function(a){try{a.select()}catch(b){}});var qg,jg=/[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/,kg=v.isWordChar=function(a){return/\w/.test(a)||a>"\x80"&&(a.toUpperCase()!=a.toLowerCase()||jg.test(a))},ng=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;qg=document.createRange?function(a,b,c,d){var e=document.createRange();return e.setEnd(d||a,c),e.setStart(a,b),e}:function(a,b,c){var d=document.body.createTextRange();try{d.moveToElementText(a.parentNode)}catch(e){return d}return d.collapse(!0),d.moveEnd("character",c),d.moveStart("character",b),d};var tg=v.contains=function(a,b){if(3==b.nodeType&&(b=b.parentNode),a.contains)return a.contains(b);do if(11==b.nodeType&&(b=b.host),b==a)return!0;while(b=b.parentNode)};d&&11>e&&(ug=function(){try{return document.activeElement}catch(a){return document.body}});var Eg,Gg,wg=v.rmClass=function(a,b){var c=a.className,d=vg(b).exec(c);if(d){var e=c.slice(d.index+d[0].length);a.className=c.slice(0,d.index)+(e?d[1]+e:"")}},xg=v.addClass=function(a,b){var c=a.className;vg(b).test(c)||(a.className+=(c?" ":"")+b)},Ag=!1,Dg=function(){if(d&&9>e)return!1;var a=pg("div");return"draggable"in a||"dragDrop"in a}(),Ig=v.splitLines=3!="\n\nb".split(/\n/).length?function(a){for(var b=0,c=[],d=a.length;d>=b;){var e=a.indexOf("\n",b);-1==e&&(e=a.length);var f=a.slice(b,"\r"==a.charAt(e-1)?e-1:e),g=f.indexOf("\r");-1!=g?(c.push(f.slice(0,g)),b+=g+1):(c.push(f),b=e+1)}return c}:function(a){return a.split(/\r\n?|\n/)},Jg=window.getSelection?function(a){try{return a.selectionStart!=a.selectionEnd}catch(b){return!1}}:function(a){try{var b=a.ownerDocument.selection.createRange()}catch(c){}return b&&b.parentElement()==a?0!=b.compareEndPoints("StartToEnd",b):!1},Kg=function(){var a=pg("div");return"oncopy"in a?!0:(a.setAttribute("oncopy","return;"),"function"==typeof a.oncopy)}(),Lg=null,Ng={3:"Enter",8:"Backspace",9:"Tab",13:"Enter",16:"Shift",17:"Ctrl",18:"Alt",19:"Pause",20:"CapsLock",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"PrintScrn",45:"Insert",46:"Delete",59:";",61:"=",91:"Mod",92:"Mod",93:"Mod",107:"=",109:"-",127:"Delete",173:"-",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",63232:"Up",63233:"Down",63234:"Left",63235:"Right",63272:"Delete",63273:"Home",63275:"End",63276:"PageUp",63277:"PageDown",63302:"Insert"};v.keyNames=Ng,function(){for(var a=0;10>a;a++)Ng[a+48]=Ng[a+96]=String(a);for(var a=65;90>=a;a++)Ng[a]=String.fromCharCode(a);for(var a=1;12>=a;a++)Ng[a+111]=Ng[a+63235]="F"+a}();var Xg,ah=function(){function c(c){return 247>=c?a.charAt(c):c>=1424&&1524>=c?"R":c>=1536&&1773>=c?b.charAt(c-1536):c>=1774&&2220>=c?"r":c>=8192&&8203>=c?"w":8204==c?"b":"L"}function j(a,b,c){this.level=a,this.from=b,this.to=c}var a="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",b="rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm",d=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,e=/[stwN]/,f=/[LRr]/,g=/[Lb1n]/,h=/[1n]/,i="L";return function(a){if(!d.test(a))return!1;for(var m,b=a.length,k=[],l=0;b>l;++l)k.push(m=c(a.charCodeAt(l)));for(var l=0,n=i;b>l;++l){var m=k[l];"m"==m?k[l]=n:n=m}for(var l=0,o=i;b>l;++l){var m=k[l];"1"==m&&"r"==o?k[l]="n":f.test(m)&&(o=m,"r"==m&&(k[l]="R"))}for(var l=1,n=k[0];b-1>l;++l){var m=k[l];"+"==m&&"1"==n&&"1"==k[l+1]?k[l]="1":","!=m||n!=k[l+1]||"1"!=n&&"n"!=n||(k[l]=n),n=m}for(var l=0;b>l;++l){var m=k[l];if(","==m)k[l]="N";else if("%"==m){for(var p=l+1;b>p&&"%"==k[p];++p);for(var q=l&&"!"==k[l-1]||b>p&&"1"==k[p]?"1":"N",r=l;p>r;++r)k[r]=q;l=p-1}}for(var l=0,o=i;b>l;++l){var m=k[l];"L"==o&&"1"==m?k[l]="L":f.test(m)&&(o=m)}for(var l=0;b>l;++l)if(e.test(k[l])){for(var p=l+1;b>p&&e.test(k[p]);++p);for(var s="L"==(l?k[l-1]:i),t="L"==(b>p?k[p]:i),q=s||t?"L":"R",r=l;p>r;++r)k[r]=q;l=p-1}for(var v,u=[],l=0;b>l;)if(g.test(k[l])){var w=l;for(++l;b>l&&g.test(k[l]);++l);u.push(new j(0,w,l))}else{var x=l,y=u.length;for(++l;b>l&&"L"!=k[l];++l);for(var r=x;l>r;)if(h.test(k[r])){r>x&&u.splice(y,0,new j(1,x,r));var z=r;for(++r;l>r&&h.test(k[r]);++r);u.splice(y,0,new j(2,z,r)),x=r}else++r;l>x&&u.splice(y,0,new j(1,x,l))}return 1==u[0].level&&(v=a.match(/^\s+/))&&(u[0].from=v[0].length,u.unshift(new j(0,0,v[0].length))),1==bg(u).level&&(v=a.match(/\s+$/))&&(bg(u).to-=v[0].length,u.push(new j(0,b-v[0].length,b))),2==u[0].level&&u.unshift(new j(1,u[0].to,u[0].to)),u[0].level!=bg(u).level&&u.push(new j(u[0].level,b,b)),u}}();return v.version="5.6.1",v}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){"use strict";function b(a){for(var b={},c=0;c<a.length;++c)b[a[c]]=!0;return b}function x(a,b){for(var d,c=!1;null!=(d=a.next());){if(c&&"/"==d){b.tokenize=null;break}c="*"==d}return["comment","comment"]}a.defineMode("css",function(b,c){function u(a,b){return s=b,a}function v(a,b){var c=a.next();if(f[c]){var d=f[c](a,b);if(d!==!1)return d}return"@"==c?(a.eatWhile(/[\w\\\-]/),u("def",a.current())):"="==c||("~"==c||"|"==c)&&a.eat("=")?u(null,"compare"):'"'==c||"'"==c?(b.tokenize=w(c),b.tokenize(a,b)):"#"==c?(a.eatWhile(/[\w\\\-]/),u("atom","hash")):"!"==c?(a.match(/^\s*\w*/),u("keyword","important")):/\d/.test(c)||"."==c&&a.eat(/\d/)?(a.eatWhile(/[\w.%]/),u("number","unit")):"-"!==c?/[,+>*\/]/.test(c)?u(null,"select-op"):"."==c&&a.match(/^-?[_a-z][_a-z0-9-]*/i)?u("qualifier","qualifier"):/[:;{}\[\]\(\)]/.test(c)?u(null,c):"u"==c&&a.match(/rl(-prefix)?\(/)||"d"==c&&a.match("omain(")||"r"==c&&a.match("egexp(")?(a.backUp(1),b.tokenize=x,u("property","word")):/[\w\\\-]/.test(c)?(a.eatWhile(/[\w\\\-]/),u("property","word")):u(null,null):/[\d.]/.test(a.peek())?(a.eatWhile(/[\w.%]/),u("number","unit")):a.match(/^-[\w\\\-]+/)?(a.eatWhile(/[\w\\\-]/),a.match(/^\s*:/,!1)?u("variable-2","variable-definition"):u("variable-2","variable")):a.match(/^\w+-/)?u("meta","meta"):void 0}function w(a){return function(b,c){for(var e,d=!1;null!=(e=b.next());){if(e==a&&!d){")"==a&&b.backUp(1);break}d=!d&&"\\"==e}return(e==a||!d&&")"!=a)&&(c.tokenize=null),u("string","string")}}function x(a,b){return a.next(),a.match(/\s*[\"\')]/,!1)?b.tokenize=null:b.tokenize=w(")"),u(null,"(")}function y(a,b,c){this.type=a,this.indent=b,this.prev=c}function z(a,b,c,d){return a.context=new y(c,b.indentation()+(d===!1?0:e),a.context),c}function A(a){return a.context.prev&&(a.context=a.context.prev),a.context.type}function B(a,b,c){return E[c.context.type](a,b,c)}function C(a,b,c,d){for(var e=d||1;e>0;e--)c.context=c.context.prev;return B(a,b,c)}function D(a){var b=a.current().toLowerCase();t=p.hasOwnProperty(b)?"atom":o.hasOwnProperty(b)?"keyword":"variable"}var d=c;c.propertyKeywords||(c=a.resolveMode("text/css")),c.inline=d.inline;var s,t,e=b.indentUnit,f=c.tokenHooks,g=c.documentTypes||{},h=c.mediaTypes||{},i=c.mediaFeatures||{},j=c.mediaValueKeywords||{},k=c.propertyKeywords||{},l=c.nonStandardPropertyKeywords||{},m=c.fontProperties||{},n=c.counterDescriptors||{},o=c.colorKeywords||{},p=c.valueKeywords||{},q=c.allowNested,r=c.supportsAtComponent===!0,E={};return E.top=function(a,b,c){if("{"==a)return z(c,b,"block");if("}"==a&&c.context.prev)return A(c);if(r&&/@component/.test(a))return z(c,b,"atComponentBlock");if(/^@(-moz-)?document$/.test(a))return z(c,b,"documentTypes");if(/^@(media|supports|(-moz-)?document|import)$/.test(a))return z(c,b,"atBlock");if(/^@(font-face|counter-style)/.test(a))return c.stateArg=a,"restricted_atBlock_before";if(/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(a))return"keyframes";if(a&&"@"==a.charAt(0))return z(c,b,"at");if("hash"==a)t="builtin";else if("word"==a)t="tag";else{if("variable-definition"==a)return"maybeprop";if("interpolation"==a)return z(c,b,"interpolation");if(":"==a)return"pseudo";if(q&&"("==a)return z(c,b,"parens")}return c.context.type},E.block=function(a,b,c){if("word"==a){var d=b.current().toLowerCase();return k.hasOwnProperty(d)?(t="property","maybeprop"):l.hasOwnProperty(d)?(t="string-2","maybeprop"):q?(t=b.match(/^\s*:(?:\s|$)/,!1)?"property":"tag","block"):(t+=" error","maybeprop")}return"meta"==a?"block":q||"hash"!=a&&"qualifier"!=a?E.top(a,b,c):(t="error","block")},E.maybeprop=function(a,b,c){return":"==a?z(c,b,"prop"):B(a,b,c)},E.prop=function(a,b,c){if(";"==a)return A(c);if("{"==a&&q)return z(c,b,"propBlock");if("}"==a||"{"==a)return C(a,b,c);if("("==a)return z(c,b,"parens");if("hash"!=a||/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(b.current())){if("word"==a)D(b);else if("interpolation"==a)return z(c,b,"interpolation")}else t+=" error";return"prop"},E.propBlock=function(a,b,c){return"}"==a?A(c):"word"==a?(t="property","maybeprop"):c.context.type},E.parens=function(a,b,c){return"{"==a||"}"==a?C(a,b,c):")"==a?A(c):"("==a?z(c,b,"parens"):"interpolation"==a?z(c,b,"interpolation"):("word"==a&&D(b),"parens")},E.pseudo=function(a,b,c){return"word"==a?(t="variable-3",c.context.type):B(a,b,c)},E.documentTypes=function(a,b,c){return"word"==a&&g.hasOwnProperty(b.current())?(t="tag",c.context.type):E.atBlock(a,b,c)},E.atBlock=function(a,b,c){if("("==a)return z(c,b,"atBlock_parens");if("}"==a||";"==a)return C(a,b,c);if("{"==a)return A(c)&&z(c,b,q?"block":"top");if("word"==a){var d=b.current().toLowerCase();t="only"==d||"not"==d||"and"==d||"or"==d?"keyword":h.hasOwnProperty(d)?"attribute":i.hasOwnProperty(d)?"property":j.hasOwnProperty(d)?"keyword":k.hasOwnProperty(d)?"property":l.hasOwnProperty(d)?"string-2":p.hasOwnProperty(d)?"atom":o.hasOwnProperty(d)?"keyword":"error"}return c.context.type},E.atComponentBlock=function(a,b,c){return"}"==a?C(a,b,c):"{"==a?A(c)&&z(c,b,q?"block":"top",!1):("word"==a&&(t="error"),c.context.type)},E.atBlock_parens=function(a,b,c){return")"==a?A(c):"{"==a||"}"==a?C(a,b,c,2):E.atBlock(a,b,c)},E.restricted_atBlock_before=function(a,b,c){return"{"==a?z(c,b,"restricted_atBlock"):"word"==a&&"@counter-style"==c.stateArg?(t="variable","restricted_atBlock_before"):B(a,b,c)},E.restricted_atBlock=function(a,b,c){return"}"==a?(c.stateArg=null,A(c)):"word"==a?(t="@font-face"==c.stateArg&&!m.hasOwnProperty(b.current().toLowerCase())||"@counter-style"==c.stateArg&&!n.hasOwnProperty(b.current().toLowerCase())?"error":"property","maybeprop"):"restricted_atBlock"},E.keyframes=function(a,b,c){return"word"==a?(t="variable","keyframes"):"{"==a?z(c,b,"top"):B(a,b,c)},E.at=function(a,b,c){return";"==a?A(c):"{"==a||"}"==a?C(a,b,c):("word"==a?t="tag":"hash"==a&&(t="builtin"),"at")},E.interpolation=function(a,b,c){return"}"==a?A(c):"{"==a||";"==a?C(a,b,c):("word"==a?t="variable":"variable"!=a&&"("!=a&&")"!=a&&(t="error"),"interpolation")},{startState:function(a){return{tokenize:null,state:c.inline?"block":"top",stateArg:null,context:new y(c.inline?"block":"top",a||0,null)}},token:function(a,b){if(!b.tokenize&&a.eatSpace())return null;var c=(b.tokenize||v)(a,b);return c&&"object"==typeof c&&(s=c[1],c=c[0]),t=c,b.state=E[b.state](s,a,b),t},indent:function(a,b){var c=a.context,d=b&&b.charAt(0),f=c.indent;
+return"prop"!=c.type||"}"!=d&&")"!=d||(c=c.prev),c.prev&&("}"!=d||"block"!=c.type&&"top"!=c.type&&"interpolation"!=c.type&&"restricted_atBlock"!=c.type?(")"==d&&("parens"==c.type||"atBlock_parens"==c.type)||"{"==d&&("at"==c.type||"atBlock"==c.type))&&(f=Math.max(0,c.indent-e),c=c.prev):(c=c.prev,f=c.indent)),f},electricChars:"}",blockCommentStart:"/*",blockCommentEnd:"*/",fold:"brace"}});var c=["domain","regexp","url","url-prefix"],d=b(c),e=["all","aural","braille","handheld","print","projection","screen","tty","tv","embossed"],f=b(e),g=["width","min-width","max-width","height","min-height","max-height","device-width","min-device-width","max-device-width","device-height","min-device-height","max-device-height","aspect-ratio","min-aspect-ratio","max-aspect-ratio","device-aspect-ratio","min-device-aspect-ratio","max-device-aspect-ratio","color","min-color","max-color","color-index","min-color-index","max-color-index","monochrome","min-monochrome","max-monochrome","resolution","min-resolution","max-resolution","scan","grid","orientation","device-pixel-ratio","min-device-pixel-ratio","max-device-pixel-ratio","pointer","any-pointer","hover","any-hover"],h=b(g),i=["landscape","portrait","none","coarse","fine","on-demand","hover","interlace","progressive"],j=b(i),k=["align-content","align-items","align-self","alignment-adjust","alignment-baseline","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","baseline-shift","binding","bleed","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-feature-settings","font-family","font-kerning","font-language-override","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-weight","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-position","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","justify-content","left","letter-spacing","line-break","line-height","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marker-offset","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","max-height","max-width","min-height","min-width","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotation","rotation-point","ruby-align","ruby-overhang","ruby-position","ruby-span","shape-image-threshold","shape-inside","shape-margin","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-outline","text-overflow","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","word-break","word-spacing","word-wrap","z-index","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","text-anchor","writing-mode"],l=b(k),m=["scrollbar-arrow-color","scrollbar-base-color","scrollbar-dark-shadow-color","scrollbar-face-color","scrollbar-highlight-color","scrollbar-shadow-color","scrollbar-3d-light-color","scrollbar-track-color","shape-inside","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","zoom"],n=b(m),o=["font-family","src","unicode-range","font-variant","font-feature-settings","font-stretch","font-weight","font-style"],p=b(o),q=["additive-symbols","fallback","negative","pad","prefix","range","speak-as","suffix","symbols","system"],r=b(q),s=["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"],t=b(s),u=["above","absolute","activeborder","additive","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alphabetic","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","attr","auto","avoid","avoid-column","avoid-page","avoid-region","background","backwards","baseline","below","bidi-override","binary","bengali","blink","block","block-axis","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","bullets","button","button-bevel","buttonface","buttonhighlight","buttonshadow","buttontext","calc","cambodian","capitalize","caps-lock-indicator","caption","captiontext","caret","cell","center","checkbox","circle","cjk-decimal","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","column","column-reverse","compact","condensed","contain","content","content-box","context-menu","continuous","copy","counter","counters","cover","crop","cross","crosshair","currentcolor","cursive","cyclic","dashed","decimal","decimal-leading-zero","default","default-button","destination-atop","destination-in","destination-out","destination-over","devanagari","disc","discard","disclosure-closed","disclosure-open","document","dot-dash","dot-dot-dash","dotted","double","down","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ethiopic-numeric","ew-resize","expanded","extends","extra-condensed","extra-expanded","fantasy","fast","fill","fixed","flat","flex","flex-end","flex-start","footnotes","forwards","from","geometricPrecision","georgian","graytext","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-flex","inline-table","inset","inside","intrinsic","invert","italic","japanese-formal","japanese-informal","justify","kannada","katakana","katakana-iroha","keep-all","khmer","korean-hangul-formal","korean-hanja-formal","korean-hanja-informal","landscape","lao","large","larger","left","level","lighter","line-through","linear","linear-gradient","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","malayalam","match","matrix","matrix3d","media-controls-background","media-current-time-display","media-fullscreen-button","media-mute-button","media-play-button","media-return-to-realtime-button","media-rewind-button","media-seek-back-button","media-seek-forward-button","media-slider","media-sliderthumb","media-time-remaining-display","media-volume-slider","media-volume-slider-container","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menulist-text","menulist-textfield","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","numbers","numeric","nw-resize","nwse-resize","oblique","octal","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","perspective","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radial-gradient","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeating-linear-gradient","repeating-radial-gradient","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","rotate","rotate3d","rotateX","rotateY","rotateZ","round","row","row-resize","row-reverse","rtl","run-in","running","s-resize","sans-serif","scale","scale3d","scaleX","scaleY","scaleZ","scroll","scrollbar","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","semi-condensed","semi-expanded","separate","serif","show","sidama","simp-chinese-formal","simp-chinese-informal","single","skew","skewX","skewY","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small","small-caps","small-caption","smaller","solid","somali","source-atop","source-in","source-out","source-over","space","space-around","space-between","spell-out","square","square-button","start","static","status-bar","stretch","stroke","sub","subpixel-antialiased","super","sw-resize","symbolic","symbols","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","tamil","telugu","text","text-bottom","text-top","textarea","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","trad-chinese-formal","trad-chinese-informal","translate","translate3d","translateX","translateY","translateZ","transparent","ultra-condensed","ultra-expanded","underline","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","var","vertical","vertical-text","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","words","wrap","wrap-reverse","x-large","x-small","xor","xx-large","xx-small"],v=b(u),w=c.concat(e).concat(g).concat(i).concat(k).concat(m).concat(s).concat(u);a.registerHelper("hintWords","css",w),a.defineMIME("text/css",{documentTypes:d,mediaTypes:f,mediaFeatures:h,mediaValueKeywords:j,propertyKeywords:l,nonStandardPropertyKeywords:n,fontProperties:p,counterDescriptors:r,colorKeywords:t,valueKeywords:v,tokenHooks:{"/":function(a,b){return a.eat("*")?(b.tokenize=x,x(a,b)):!1}},name:"css"}),a.defineMIME("text/x-scss",{mediaTypes:f,mediaFeatures:h,mediaValueKeywords:j,propertyKeywords:l,nonStandardPropertyKeywords:n,colorKeywords:t,valueKeywords:v,fontProperties:p,allowNested:!0,tokenHooks:{"/":function(a,b){return a.eat("/")?(a.skipToEnd(),["comment","comment"]):a.eat("*")?(b.tokenize=x,x(a,b)):["operator","operator"]},":":function(a){return a.match(/\s*\{/)?[null,"{"]:!1},$:function(a){return a.match(/^[\w-]+/),a.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"]},"#":function(a){return a.eat("{")?[null,"interpolation"]:!1}},name:"css",helperType:"scss"}),a.defineMIME("text/x-less",{mediaTypes:f,mediaFeatures:h,mediaValueKeywords:j,propertyKeywords:l,nonStandardPropertyKeywords:n,colorKeywords:t,valueKeywords:v,fontProperties:p,allowNested:!0,tokenHooks:{"/":function(a,b){return a.eat("/")?(a.skipToEnd(),["comment","comment"]):a.eat("*")?(b.tokenize=x,x(a,b)):["operator","operator"]},"@":function(a){return a.eat("{")?[null,"interpolation"]:a.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/,!1)?!1:(a.eatWhile(/[\w\\\-]/),a.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"])},"&":function(){return["atom","atom"]}},name:"css",helperType:"less"}),a.defineMIME("text/x-gss",{documentTypes:d,mediaTypes:f,mediaFeatures:h,propertyKeywords:l,nonStandardPropertyKeywords:n,fontProperties:p,counterDescriptors:r,colorKeywords:t,valueKeywords:v,supportsAtComponent:!0,tokenHooks:{"/":function(a,b){return a.eat("*")?(b.tokenize=x,x(a,b)):!1}},name:"css",helperType:"gss"})}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror"),require("../xml/xml"),require("../javascript/javascript"),require("../css/css")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","../xml/xml","../javascript/javascript","../css/css"],a):a(CodeMirror)}(function(a){"use strict";function c(a,b,c){var d=a.current(),e=d.search(b);return e>-1?a.backUp(d.length-e):d.match(/<\/?$/)&&(a.backUp(d.length),a.match(b,!1)||a.match(d)),c}function e(a){var b=d[a];return b?b:d[a]=new RegExp("\\s+"+a+"\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*")}function f(a,b){for(var d,c=a.pos;c>=0&&"<"!==a.string.charAt(c);)c--;return 0>c?c:(d=a.string.slice(c,a.pos).match(e(b)))?d[2]:""}function g(a,b){return new RegExp((b?"^":"")+"</s*"+a+"s*>","i")}function h(a,b){for(var c in a)for(var d=b[c]||(b[c]=[]),e=a[c],f=e.length-1;f>=0;f--)d.unshift(e[f])}function i(a,b){for(var c=0;c<a.length;c++){var d=a[c];if(!d[0]||d[1].test(f(b,d[0])))return d[2]}}var b={script:[["lang",/(javascript|babel)/i,"javascript"],["type",/^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,"javascript"],["type",/./,"text/plain"],[null,null,"javascript"]],style:[["lang",/^css$/i,"css"],["type",/^(text\/)?(x-)?(stylesheet|css)$/i,"css"],["type",/./,"text/plain"],[null,null,"css"]]},d={};a.defineMode("htmlmixed",function(d,e){function n(b,e){var m,h=e.htmlState.tagName,k=h&&j[h.toLowerCase()],l=f.token(b,e.htmlState);if(k&&/\btag\b/.test(l)&&">"===b.current()&&(m=i(k,b))){var o=a.getMode(d,m),p=g(h,!0),q=g(h,!1);e.token=function(a,b){return a.match(p,!1)?(b.token=n,b.localState=b.localMode=null,null):c(a,q,b.localMode.token(a,b.localState))},e.localMode=o,e.localState=a.startState(o,f.indent(e.htmlState,""))}return l}var f=a.getMode(d,{name:"xml",htmlMode:!0,multilineTagIndentFactor:e.multilineTagIndentFactor,multilineTagIndentPastTag:e.multilineTagIndentPastTag}),j={},k=e&&e.tags,l=e&&e.scriptTypes;if(h(b,j),k&&h(k,j),l)for(var m=l.length-1;m>=0;m--)j.script.unshift(["type",l[m].matches,l[m].mode]);return{startState:function(){var a=f.startState();return{token:n,localMode:null,localState:null,htmlState:a}},copyState:function(b){var c;return b.localState&&(c=a.copyState(b.localMode,b.localState)),{token:b.token,localMode:b.localMode,localState:c,htmlState:a.copyState(f,b.htmlState)}},token:function(a,b){return b.token(a,b)},indent:function(b,c){return!b.localMode||/^\s*<\//.test(c)?f.indent(b.htmlState,c):b.localMode.indent?b.localMode.indent(b.localState,c):a.Pass},innerMode:function(a){return{state:a.localState||a.htmlState,mode:a.localMode||f}}}},"xml","javascript","css"),a.defineMIME("text/html","htmlmixed")}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){"use strict";a.defineMode("javascript",function(b,c){function m(a){for(var c,b=!1,d=!1;null!=(c=a.next());){if(!b){if("/"==c&&!d)return;"["==c?d=!0:d&&"]"==c&&(d=!1)}b=!b&&"\\"==c}}function p(a,b,c){return n=a,o=c,b}function q(a,b){var c=a.next();if('"'==c||"'"==c)return b.tokenize=r(c),b.tokenize(a,b);if("."==c&&a.match(/^\d+(?:[eE][+\-]?\d+)?/))return p("number","number");if("."==c&&a.match(".."))return p("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(c))return p(c);if("="==c&&a.eat(">"))return p("=>","operator");if("0"==c&&a.eat(/x/i))return a.eatWhile(/[\da-f]/i),p("number","number");if(/\d/.test(c))return a.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/),p("number","number");if("/"==c)return a.eat("*")?(b.tokenize=s,s(a,b)):a.eat("/")?(a.skipToEnd(),p("comment","comment")):"operator"==b.lastType||"keyword c"==b.lastType||"sof"==b.lastType||/^[\[{}\(,;:]$/.test(b.lastType)?(m(a),a.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/),p("regexp","string-2")):(a.eatWhile(k),p("operator","operator",a.current()));if("`"==c)return b.tokenize=t,t(a,b);if("#"==c)return a.skipToEnd(),p("error","error");if(k.test(c))return a.eatWhile(k),p("operator","operator",a.current());if(i.test(c)){a.eatWhile(i);var d=a.current(),e=j.propertyIsEnumerable(d)&&j[d];return e&&"."!=b.lastType?p(e.type,e.style,d):p("variable","variable",d)}}function r(a){return function(b,c){var e,d=!1;if(f&&"@"==b.peek()&&b.match(l))return c.tokenize=q,p("jsonld-keyword","meta");for(;null!=(e=b.next())&&(e!=a||d);)d=!d&&"\\"==e;return d||(c.tokenize=q),p("string","string")}}function s(a,b){for(var d,c=!1;d=a.next();){if("/"==d&&c){b.tokenize=q;break}c="*"==d}return p("comment","comment")}function t(a,b){for(var d,c=!1;null!=(d=a.next());){if(!c&&("`"==d||"$"==d&&a.eat("{"))){b.tokenize=q;break}c=!c&&"\\"==d}return p("quasi","string-2",a.current())}function v(a,b){b.fatArrowAt&&(b.fatArrowAt=null);var c=a.string.indexOf("=>",a.start);if(!(0>c)){for(var d=0,e=!1,f=c-1;f>=0;--f){var g=a.string.charAt(f),h=u.indexOf(g);if(h>=0&&3>h){if(!d){++f;break}if(0==--d)break}else if(h>=3&&6>h)++d;else if(i.test(g))e=!0;else{if(/["'\/]/.test(g))return;if(e&&!d){++f;break}}}e&&!d&&(b.fatArrowAt=f)}}function x(a,b,c,d,e,f){this.indented=a,this.column=b,this.type=c,this.prev=e,this.info=f,null!=d&&(this.align=d)}function y(a,b){for(var c=a.localVars;c;c=c.next)if(c.name==b)return!0;for(var d=a.context;d;d=d.prev)for(var c=d.vars;c;c=c.next)if(c.name==b)return!0}function z(a,b,c,d,e){var f=a.cc;for(A.state=a,A.stream=e,A.marked=null,A.cc=f,A.style=b,a.lexical.hasOwnProperty("align")||(a.lexical.align=!0);;){var h=f.length?f.pop():g?L:K;if(h(c,d)){for(;f.length&&f[f.length-1].lex;)f.pop()();return A.marked?A.marked:"variable"==c&&y(a,d)?"variable-2":b}}}function B(){for(var a=arguments.length-1;a>=0;a--)A.cc.push(arguments[a])}function C(){return B.apply(null,arguments),!0}function D(a){function b(b){for(var c=b;c;c=c.next)if(c.name==a)return!0;return!1}var d=A.state;if(d.context){if(A.marked="def",b(d.localVars))return;d.localVars={name:a,next:d.localVars}}else{if(b(d.globalVars))return;c.globalVars&&(d.globalVars={name:a,next:d.globalVars})}}function F(){A.state.context={prev:A.state.context,vars:A.state.localVars},A.state.localVars=E}function G(){A.state.localVars=A.state.context.vars,A.state.context=A.state.context.prev}function H(a,b){var c=function(){var c=A.state,d=c.indented;if("stat"==c.lexical.type)d=c.lexical.indented;else for(var e=c.lexical;e&&")"==e.type&&e.align;e=e.prev)d=e.indented;c.lexical=new x(d,A.stream.column(),a,null,c.lexical,b)};return c.lex=!0,c}function I(){var a=A.state;a.lexical.prev&&(")"==a.lexical.type&&(a.indented=a.lexical.indented),a.lexical=a.lexical.prev)}function J(a){function b(c){return c==a?C():";"==a?B():C(b)}return b}function K(a,b){return"var"==a?C(H("vardef",b.length),fa,J(";"),I):"keyword a"==a?C(H("form"),L,K,I):"keyword b"==a?C(H("form"),K,I):"{"==a?C(H("}"),ba,I):";"==a?C():"if"==a?("else"==A.state.lexical.info&&A.state.cc[A.state.cc.length-1]==I&&A.state.cc.pop()(),C(H("form"),L,K,I,ka)):"function"==a?C(qa):"for"==a?C(H("form"),la,K,I):"variable"==a?C(H("stat"),W):"switch"==a?C(H("form"),L,H("}","switch"),J("{"),ba,I,I):"case"==a?C(L,J(":")):"default"==a?C(J(":")):"catch"==a?C(H("form"),F,J("("),ra,J(")"),K,I,G):"class"==a?C(H("form"),sa,I):"export"==a?C(H("form"),wa,I):"import"==a?C(H("form"),xa,I):B(H("stat"),L,J(";"),I)}function L(a){return N(a,!1)}function M(a){return N(a,!0)}function N(a,b){if(A.state.fatArrowAt==A.stream.start){var c=b?V:U;if("("==a)return C(F,H(")"),_(ga,")"),I,J("=>"),c,G);if("variable"==a)return B(F,ga,J("=>"),c,G)}var d=b?R:Q;return w.hasOwnProperty(a)?C(d):"async"==a?C(L):"function"==a?C(qa,d):"keyword c"==a?C(b?P:O):"("==a?C(H(")"),O,Da,J(")"),I,d):"operator"==a||"spread"==a?C(b?M:L):"["==a?C(H("]"),Ba,I,d):"{"==a?aa(Y,"}",null,d):"quasi"==a?B(S,d):C()}function O(a){return a.match(/[;\}\)\],]/)?B():B(L)}function P(a){return a.match(/[;\}\)\],]/)?B():B(M)}function Q(a,b){return","==a?C(L):R(a,b,!1)}function R(a,b,c){var d=0==c?Q:R,e=0==c?L:M;return"=>"==a?C(F,c?V:U,G):"operator"==a?/\+\+|--/.test(b)?C(d):"?"==b?C(L,J(":"),e):C(e):"quasi"==a?B(S,d):";"!=a?"("==a?aa(M,")","call",d):"."==a?C(X,d):"["==a?C(H("]"),O,J("]"),I,d):void 0:void 0}function S(a,b){return"quasi"!=a?B():"${"!=b.slice(b.length-2)?C(S):C(L,T)}function T(a){return"}"==a?(A.marked="string-2",A.state.tokenize=t,C(S)):void 0}function U(a){return v(A.stream,A.state),B("{"==a?K:L)}function V(a){return v(A.stream,A.state),B("{"==a?K:M)}function W(a){return":"==a?C(I,K):B(Q,J(";"),I)}function X(a){return"variable"==a?(A.marked="property",C()):void 0}function Y(a,b){return"async"==a?C(Y):"variable"==a||"keyword"==A.style?(A.marked="property",C("get"==b||"set"==b?Z:$)):"number"==a||"string"==a?(A.marked=f?"property":A.style+" property",C($)):"jsonld-keyword"==a?C($):"["==a?C(L,J("]"),$):void 0}function Z(a){return"variable"!=a?B($):(A.marked="property",C(qa))}function $(a){return":"==a?C(M):"("==a?B(qa):void 0}function _(a,b){function c(d){if(","==d){var e=A.state.lexical;return"call"==e.info&&(e.pos=(e.pos||0)+1),C(a,c)}return d==b?C():C(J(b))}return function(d){return d==b?C():B(a,c)}}function aa(a,b,c){for(var d=3;d<arguments.length;d++)A.cc.push(arguments[d]);return C(H(b,c),_(a,b),I)}function ba(a){return"}"==a?C():B(K,ba)}function ca(a){return h&&":"==a?C(ea):void 0}function da(a,b){return"="==b?C(M):void 0}function ea(a){return"variable"==a?(A.marked="variable-3",C()):void 0}function fa(){return B(ga,ca,ia,ja)}function ga(a,b){return"variable"==a?(D(b),C()):"["==a?aa(ga,"]"):"{"==a?aa(ha,"}"):void 0}function ha(a,b){return"variable"!=a||A.stream.match(/^\s*:/,!1)?("variable"==a&&(A.marked="property"),C(J(":"),ga,ia)):(D(b),C(ia))}function ia(a,b){return"="==b?C(M):void 0}function ja(a){return","==a?C(fa):void 0}function ka(a,b){return"keyword b"==a&&"else"==b?C(H("form","else"),K,I):void 0}function la(a){return"("==a?C(H(")"),ma,J(")"),I):void 0}function ma(a){return"var"==a?C(fa,J(";"),oa):";"==a?C(oa):"variable"==a?C(na):B(L,J(";"),oa)}function na(a,b){return"in"==b||"of"==b?(A.marked="keyword",C(L)):C(Q,oa)}function oa(a,b){return";"==a?C(pa):"in"==b||"of"==b?(A.marked="keyword",C(L)):B(L,J(";"),pa)}function pa(a){")"!=a&&C(L)}function qa(a,b){return"*"==b?(A.marked="keyword",C(qa)):"variable"==a?(D(b),C(qa)):"("==a?C(F,H(")"),_(ra,")"),I,K,G):void 0}function ra(a){return"spread"==a?C(ra):B(ga,ca,da)}function sa(a,b){return"variable"==a?(D(b),C(ta)):void 0}function ta(a,b){return"extends"==b?C(L,ta):"{"==a?C(H("}"),ua,I):void 0}function ua(a,b){return"variable"==a||"keyword"==A.style?"static"==b?(A.marked="keyword",C(ua)):(A.marked="property","get"==b||"set"==b?C(va,qa,ua):C(qa,ua)):"*"==b?(A.marked="keyword",C(ua)):";"==a?C(ua):"}"==a?C():void 0}function va(a){return"variable"!=a?B():(A.marked="property",C())}function wa(a,b){return"*"==b?(A.marked="keyword",C(Aa,J(";"))):"default"==b?(A.marked="keyword",C(L,J(";"))):B(K)}function xa(a){return"string"==a?C():B(ya,Aa)}function ya(a,b){return"{"==a?aa(ya,"}"):("variable"==a&&D(b),"*"==b&&(A.marked="keyword"),C(za))}function za(a,b){return"as"==b?(A.marked="keyword",C(ya)):void 0}function Aa(a,b){return"from"==b?(A.marked="keyword",C(L)):void 0}function Ba(a){return"]"==a?C():B(M,Ca)}function Ca(a){return"for"==a?B(Da,J("]")):","==a?C(_(P,"]")):B(_(M,"]"))}function Da(a){return"for"==a?C(la,Da):"if"==a?C(L,Da):void 0}function Ea(a,b){return"operator"==a.lastType||","==a.lastType||k.test(b.charAt(0))||/[,.]/.test(b.charAt(0))}var n,o,d=b.indentUnit,e=c.statementIndent,f=c.jsonld,g=c.json||f,h=c.typescript,i=c.wordCharacters||/[\w$\xa1-\uffff]/,j=function(){function a(a){return{type:a,style:"keyword"}}var b=a("keyword a"),c=a("keyword b"),d=a("keyword c"),e=a("operator"),f={type:"atom",style:"atom"},g={"if":a("if"),"while":b,"with":b,"else":c,"do":c,"try":c,"finally":c,"return":d,"break":d,"continue":d,"new":d,"delete":d,"throw":d,"debugger":d,"var":a("var"),"const":a("var"),let:a("var"),async:a("async"),"function":a("function"),"catch":a("catch"),"for":a("for"),"switch":a("switch"),"case":a("case"),"default":a("default"),"in":e,"typeof":e,"instanceof":e,"true":f,"false":f,"null":f,undefined:f,NaN:f,Infinity:f,"this":a("this"),"class":a("class"),"super":a("atom"),await:d,"yield":d,"export":a("export"),"import":a("import"),"extends":d};if(h){var i={type:"variable",style:"variable-3"},j={"interface":a("interface"),"extends":a("extends"),constructor:a("constructor"),"public":a("public"),"private":a("private"),"protected":a("protected"),"static":a("static"),string:i,number:i,bool:i,any:i};for(var k in j)g[k]=j[k]}return g}(),k=/[+\-*&%=<>!?|~^]/,l=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/,u="([{}])",w={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,"this":!0,"jsonld-keyword":!0},A={state:null,column:null,marked:null,cc:null},E={name:"this",next:{name:"arguments"}};return I.lex=!0,{startState:function(a){var b={tokenize:q,lastType:"sof",cc:[],lexical:new x((a||0)-d,0,"block",!1),localVars:c.localVars,context:c.localVars&&{vars:c.localVars},indented:0};return c.globalVars&&"object"==typeof c.globalVars&&(b.globalVars=c.globalVars),b},token:function(a,b){if(a.sol()&&(b.lexical.hasOwnProperty("align")||(b.lexical.align=!1),b.indented=a.indentation(),v(a,b)),b.tokenize!=s&&a.eatSpace())return null;var c=b.tokenize(a,b);return"comment"==n?c:(b.lastType="operator"!=n||"++"!=o&&"--"!=o?n:"incdec",z(b,c,n,o,a))},indent:function(b,f){if(b.tokenize==s)return a.Pass;if(b.tokenize!=q)return 0;var g=f&&f.charAt(0),h=b.lexical;if(!/^\s*else\b/.test(f))for(var i=b.cc.length-1;i>=0;--i){var j=b.cc[i];if(j==I)h=h.prev;else if(j!=ka)break}"stat"==h.type&&"}"==g&&(h=h.prev),e&&")"==h.type&&"stat"==h.prev.type&&(h=h.prev);var k=h.type,l=g==k;return"vardef"==k?h.indented+("operator"==b.lastType||","==b.lastType?h.info+1:0):"form"==k&&"{"==g?h.indented:"form"==k?h.indented+d:"stat"==k?h.indented+(Ea(b,f)?e||d:0):"switch"!=h.info||l||0==c.doubleIndentSwitch?h.align?h.column+(l?0:1):h.indented+(l?0:d):h.indented+(/^(?:case|default)\b/.test(f)?d:2*d)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:g?null:"/*",blockCommentEnd:g?null:"*/",lineComment:g?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:g?"json":"javascript",jsonldMode:f,jsonMode:g}}),a.registerHelper("wordChars","javascript",/[\w$]/),a.defineMIME("text/javascript","javascript"),a.defineMIME("text/ecmascript","javascript"),a.defineMIME("application/javascript","javascript"),
+a.defineMIME("application/x-javascript","javascript"),a.defineMIME("application/ecmascript","javascript"),a.defineMIME("application/json",{name:"javascript",json:!0}),a.defineMIME("application/x-json",{name:"javascript",json:!0}),a.defineMIME("application/ld+json",{name:"javascript",jsonld:!0}),a.defineMIME("text/typescript",{name:"javascript",typescript:!0}),a.defineMIME("application/typescript",{name:"javascript",typescript:!0})}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){"use strict";function b(a,b){return a.string.charAt(a.pos+(b||0))}function c(a,b){if(b){var c=a.pos-b;return a.string.substr(c>=0?c:0,b)}return a.string.substr(0,a.pos-1)}function d(a,b){var c=a.string.length,d=c-a.pos+1;return a.string.substr(a.pos,b&&c>b?b:d)}function e(a,b){var d,c=a.pos+b;0>=c?a.pos=0:c>=(d=a.string.length-1)?a.pos=d:a.pos=c}a.defineMode("perl",function(){function h(a,b,c,d,e){return b.chain=null,b.style=null,b.tail=null,b.tokenize=function(a,b){for(var g,f=!1,h=0;g=a.next();){if(g===c[h]&&!f)return void 0!==c[++h]?(b.chain=c[h],b.style=d,b.tail=e):e&&a.eatWhile(e),b.tokenize=j,d;f=!f&&"\\"==g}return d},b.tokenize(a,b)}function i(a,b,c){return b.tokenize=function(a,b){return a.string==c&&(b.tokenize=j),a.skipToEnd(),"string"},b.tokenize(a,b)}function j(j,k){if(j.eatSpace())return null;if(k.chain)return h(j,k,k.chain,k.style,k.tail);if(j.match(/^\-?[\d\.]/,!1)&&j.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/))return"number";if(j.match(/^<<(?=\w)/))return j.eatWhile(/\w/),i(j,k,j.current().substr(2));if(j.sol()&&j.match(/^\=item(?!\w)/))return i(j,k,"=cut");var l=j.next();if('"'==l||"'"==l){if(c(j,3)=="<<"+l){var m=j.pos;j.eatWhile(/\w/);var n=j.current().substr(1);if(n&&j.eat(l))return i(j,k,n);j.pos=m}return h(j,k,[l],"string")}if("q"==l){var o=b(j,-2);if(!o||!/\w/.test(o))if(o=b(j,0),"x"==o){if(o=b(j,1),"("==o)return e(j,2),h(j,k,[")"],f,g);if("["==o)return e(j,2),h(j,k,["]"],f,g);if("{"==o)return e(j,2),h(j,k,["}"],f,g);if("<"==o)return e(j,2),h(j,k,[">"],f,g);if(/[\^'"!~\/]/.test(o))return e(j,1),h(j,k,[j.eat(o)],f,g)}else if("q"==o){if(o=b(j,1),"("==o)return e(j,2),h(j,k,[")"],"string");if("["==o)return e(j,2),h(j,k,["]"],"string");if("{"==o)return e(j,2),h(j,k,["}"],"string");if("<"==o)return e(j,2),h(j,k,[">"],"string");if(/[\^'"!~\/]/.test(o))return e(j,1),h(j,k,[j.eat(o)],"string")}else if("w"==o){if(o=b(j,1),"("==o)return e(j,2),h(j,k,[")"],"bracket");if("["==o)return e(j,2),h(j,k,["]"],"bracket");if("{"==o)return e(j,2),h(j,k,["}"],"bracket");if("<"==o)return e(j,2),h(j,k,[">"],"bracket");if(/[\^'"!~\/]/.test(o))return e(j,1),h(j,k,[j.eat(o)],"bracket")}else if("r"==o){if(o=b(j,1),"("==o)return e(j,2),h(j,k,[")"],f,g);if("["==o)return e(j,2),h(j,k,["]"],f,g);if("{"==o)return e(j,2),h(j,k,["}"],f,g);if("<"==o)return e(j,2),h(j,k,[">"],f,g);if(/[\^'"!~\/]/.test(o))return e(j,1),h(j,k,[j.eat(o)],f,g)}else if(/[\^'"!~\/(\[{<]/.test(o)){if("("==o)return e(j,1),h(j,k,[")"],"string");if("["==o)return e(j,1),h(j,k,["]"],"string");if("{"==o)return e(j,1),h(j,k,["}"],"string");if("<"==o)return e(j,1),h(j,k,[">"],"string");if(/[\^'"!~\/]/.test(o))return h(j,k,[j.eat(o)],"string")}}if("m"==l){var o=b(j,-2);if((!o||!/\w/.test(o))&&(o=j.eat(/[(\[{<\^'"!~\/]/))){if(/[\^'"!~\/]/.test(o))return h(j,k,[o],f,g);if("("==o)return h(j,k,[")"],f,g);if("["==o)return h(j,k,["]"],f,g);if("{"==o)return h(j,k,["}"],f,g);if("<"==o)return h(j,k,[">"],f,g)}}if("s"==l){var o=/[\/>\]})\w]/.test(b(j,-2));if(!o&&(o=j.eat(/[(\[{<\^'"!~\/]/)))return"["==o?h(j,k,["]","]"],f,g):"{"==o?h(j,k,["}","}"],f,g):"<"==o?h(j,k,[">",">"],f,g):"("==o?h(j,k,[")",")"],f,g):h(j,k,[o,o],f,g)}if("y"==l){var o=/[\/>\]})\w]/.test(b(j,-2));if(!o&&(o=j.eat(/[(\[{<\^'"!~\/]/)))return"["==o?h(j,k,["]","]"],f,g):"{"==o?h(j,k,["}","}"],f,g):"<"==o?h(j,k,[">",">"],f,g):"("==o?h(j,k,[")",")"],f,g):h(j,k,[o,o],f,g)}if("t"==l){var o=/[\/>\]})\w]/.test(b(j,-2));if(!o&&(o=j.eat("r"),o&&(o=j.eat(/[(\[{<\^'"!~\/]/))))return"["==o?h(j,k,["]","]"],f,g):"{"==o?h(j,k,["}","}"],f,g):"<"==o?h(j,k,[">",">"],f,g):"("==o?h(j,k,[")",")"],f,g):h(j,k,[o,o],f,g)}if("`"==l)return h(j,k,[l],"variable-2");if("/"==l)return/~\s*$/.test(c(j))?h(j,k,[l],f,g):"operator";if("$"==l){var m=j.pos;if(j.eatWhile(/\d/)||j.eat("{")&&j.eatWhile(/\d/)&&j.eat("}"))return"variable-2";j.pos=m}if(/[$@%]/.test(l)){var m=j.pos;if(j.eat("^")&&j.eat(/[A-Z]/)||!/[@$%&]/.test(b(j,-2))&&j.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)){var o=j.current();if(a[o])return"variable-2"}j.pos=m}if(/[$@%&]/.test(l)&&(j.eatWhile(/[\w$\[\]]/)||j.eat("{")&&j.eatWhile(/[\w$\[\]]/)&&j.eat("}"))){var o=j.current();return a[o]?"variable-2":"variable"}if("#"==l&&"$"!=b(j,-2))return j.skipToEnd(),"comment";if(/[:+\-\^*$&%@=<>!?|\/~\.]/.test(l)){var m=j.pos;if(j.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/),a[j.current()])return"operator";j.pos=m}if("_"==l&&1==j.pos){if("_END__"==d(j,6))return h(j,k,["\x00"],"comment");if("_DATA__"==d(j,7))return h(j,k,["\x00"],"variable-2");if("_C__"==d(j,7))return h(j,k,["\x00"],"string")}if(/\w/.test(l)){var m=j.pos;if("{"==b(j,-2)&&("}"==b(j,0)||j.eatWhile(/\w/)&&"}"==b(j,0)))return"string";j.pos=m}if(/[A-Z]/.test(l)){var p=b(j,-2),m=j.pos;if(j.eatWhile(/[A-Z_]/),!/[\da-z]/.test(b(j,0))){var o=a[j.current()];return o?(o[1]&&(o=o[0]),":"!=p?1==o?"keyword":2==o?"def":3==o?"atom":4==o?"operator":5==o?"variable-2":"meta":"meta"):"meta"}j.pos=m}if(/[a-zA-Z_]/.test(l)){var p=b(j,-2);j.eatWhile(/\w/);var o=a[j.current()];return o?(o[1]&&(o=o[0]),":"!=p?1==o?"keyword":2==o?"def":3==o?"atom":4==o?"operator":5==o?"variable-2":"meta":"meta"):"meta"}return null}var a={"->":4,"++":4,"--":4,"**":4,"=~":4,"!~":4,"*":4,"/":4,"%":4,x:4,"+":4,"-":4,".":4,"<<":4,">>":4,"<":4,">":4,"<=":4,">=":4,lt:4,gt:4,le:4,ge:4,"==":4,"!=":4,"<=>":4,eq:4,ne:4,cmp:4,"~~":4,"&":4,"|":4,"^":4,"&&":4,"||":4,"//":4,"..":4,"...":4,"?":4,":":4,"=":4,"+=":4,"-=":4,"*=":4,",":4,"=>":4,"::":4,not:4,and:4,or:4,xor:4,BEGIN:[5,1],END:[5,1],PRINT:[5,1],PRINTF:[5,1],GETC:[5,1],READ:[5,1],READLINE:[5,1],DESTROY:[5,1],TIE:[5,1],TIEHANDLE:[5,1],UNTIE:[5,1],STDIN:5,STDIN_TOP:5,STDOUT:5,STDOUT_TOP:5,STDERR:5,STDERR_TOP:5,$ARG:5,$_:5,"@ARG":5,"@_":5,$LIST_SEPARATOR:5,'$"':5,$PROCESS_ID:5,$PID:5,$$:5,$REAL_GROUP_ID:5,$GID:5,"$(":5,$EFFECTIVE_GROUP_ID:5,$EGID:5,"$)":5,$PROGRAM_NAME:5,$0:5,$SUBSCRIPT_SEPARATOR:5,$SUBSEP:5,"$;":5,$REAL_USER_ID:5,$UID:5,"$<":5,$EFFECTIVE_USER_ID:5,$EUID:5,"$>":5,$a:5,$b:5,$COMPILING:5,"$^C":5,$DEBUGGING:5,"$^D":5,"${^ENCODING}":5,$ENV:5,"%ENV":5,$SYSTEM_FD_MAX:5,"$^F":5,"@F":5,"${^GLOBAL_PHASE}":5,"$^H":5,"%^H":5,"@INC":5,"%INC":5,$INPLACE_EDIT:5,"$^I":5,"$^M":5,$OSNAME:5,"$^O":5,"${^OPEN}":5,$PERLDB:5,"$^P":5,$SIG:5,"%SIG":5,$BASETIME:5,"$^T":5,"${^TAINT}":5,"${^UNICODE}":5,"${^UTF8CACHE}":5,"${^UTF8LOCALE}":5,$PERL_VERSION:5,"$^V":5,"${^WIN32_SLOPPY_STAT}":5,$EXECUTABLE_NAME:5,"$^X":5,$1:5,$MATCH:5,"$&":5,"${^MATCH}":5,$PREMATCH:5,"$`":5,"${^PREMATCH}":5,$POSTMATCH:5,"$'":5,"${^POSTMATCH}":5,$LAST_PAREN_MATCH:5,"$+":5,$LAST_SUBMATCH_RESULT:5,"$^N":5,"@LAST_MATCH_END":5,"@+":5,"%LAST_PAREN_MATCH":5,"%+":5,"@LAST_MATCH_START":5,"@-":5,"%LAST_MATCH_START":5,"%-":5,$LAST_REGEXP_CODE_RESULT:5,"$^R":5,"${^RE_DEBUG_FLAGS}":5,"${^RE_TRIE_MAXBUF}":5,$ARGV:5,"@ARGV":5,ARGV:5,ARGVOUT:5,$OUTPUT_FIELD_SEPARATOR:5,$OFS:5,"$,":5,$INPUT_LINE_NUMBER:5,$NR:5,"$.":5,$INPUT_RECORD_SEPARATOR:5,$RS:5,"$/":5,$OUTPUT_RECORD_SEPARATOR:5,$ORS:5,"$\\":5,$OUTPUT_AUTOFLUSH:5,"$|":5,$ACCUMULATOR:5,"$^A":5,$FORMAT_FORMFEED:5,"$^L":5,$FORMAT_PAGE_NUMBER:5,"$%":5,$FORMAT_LINES_LEFT:5,"$-":5,$FORMAT_LINE_BREAK_CHARACTERS:5,"$:":5,$FORMAT_LINES_PER_PAGE:5,"$=":5,$FORMAT_TOP_NAME:5,"$^":5,$FORMAT_NAME:5,"$~":5,"${^CHILD_ERROR_NATIVE}":5,$EXTENDED_OS_ERROR:5,"$^E":5,$EXCEPTIONS_BEING_CAUGHT:5,"$^S":5,$WARNING:5,"$^W":5,"${^WARNING_BITS}":5,$OS_ERROR:5,$ERRNO:5,"$!":5,"%OS_ERROR":5,"%ERRNO":5,"%!":5,$CHILD_ERROR:5,"$?":5,$EVAL_ERROR:5,"$@":5,$OFMT:5,"$#":5,"$*":5,$ARRAY_BASE:5,"$[":5,$OLD_PERL_VERSION:5,"$]":5,"if":[1,1],elsif:[1,1],"else":[1,1],"while":[1,1],unless:[1,1],"for":[1,1],foreach:[1,1],abs:1,accept:1,alarm:1,atan2:1,bind:1,binmode:1,bless:1,bootstrap:1,"break":1,caller:1,chdir:1,chmod:1,chomp:1,chop:1,chown:1,chr:1,chroot:1,close:1,closedir:1,connect:1,"continue":[1,1],cos:1,crypt:1,dbmclose:1,dbmopen:1,"default":1,defined:1,"delete":1,die:1,"do":1,dump:1,each:1,endgrent:1,endhostent:1,endnetent:1,endprotoent:1,endpwent:1,endservent:1,eof:1,eval:1,exec:1,exists:1,exit:1,exp:1,fcntl:1,fileno:1,flock:1,fork:1,format:1,formline:1,getc:1,getgrent:1,getgrgid:1,getgrnam:1,gethostbyaddr:1,gethostbyname:1,gethostent:1,getlogin:1,getnetbyaddr:1,getnetbyname:1,getnetent:1,getpeername:1,getpgrp:1,getppid:1,getpriority:1,getprotobyname:1,getprotobynumber:1,getprotoent:1,getpwent:1,getpwnam:1,getpwuid:1,getservbyname:1,getservbyport:1,getservent:1,getsockname:1,getsockopt:1,given:1,glob:1,gmtime:1,"goto":1,grep:1,hex:1,"import":1,index:1,"int":1,ioctl:1,join:1,keys:1,kill:1,last:1,lc:1,lcfirst:1,length:1,link:1,listen:1,local:2,localtime:1,lock:1,log:1,lstat:1,m:null,map:1,mkdir:1,msgctl:1,msgget:1,msgrcv:1,msgsnd:1,my:2,"new":1,next:1,no:1,oct:1,open:1,opendir:1,ord:1,our:2,pack:1,"package":1,pipe:1,pop:1,pos:1,print:1,printf:1,prototype:1,push:1,q:null,qq:null,qr:null,quotemeta:null,qw:null,qx:null,rand:1,read:1,readdir:1,readline:1,readlink:1,readpipe:1,recv:1,redo:1,ref:1,rename:1,require:1,reset:1,"return":1,reverse:1,rewinddir:1,rindex:1,rmdir:1,s:null,say:1,scalar:1,seek:1,seekdir:1,select:1,semctl:1,semget:1,semop:1,send:1,setgrent:1,sethostent:1,setnetent:1,setpgrp:1,setpriority:1,setprotoent:1,setpwent:1,setservent:1,setsockopt:1,shift:1,shmctl:1,shmget:1,shmread:1,shmwrite:1,shutdown:1,sin:1,sleep:1,socket:1,socketpair:1,sort:1,splice:1,split:1,sprintf:1,sqrt:1,srand:1,stat:1,state:1,study:1,sub:1,substr:1,symlink:1,syscall:1,sysopen:1,sysread:1,sysseek:1,system:1,syswrite:1,tell:1,telldir:1,tie:1,tied:1,time:1,times:1,tr:null,truncate:1,uc:1,ucfirst:1,umask:1,undef:1,unlink:1,unpack:1,unshift:1,untie:1,use:1,utime:1,values:1,vec:1,wait:1,waitpid:1,wantarray:1,warn:1,when:1,write:1,y:null},f="string-2",g=/[goseximacplud]/;return{startState:function(){return{tokenize:j,chain:null,style:null,tail:null}},token:function(a,b){return(b.tokenize||j)(a,b)},lineComment:"#"}}),a.registerHelper("wordChars","perl",/[\w$]/),a.defineMIME("text/x-perl","perl")}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){"use strict";function b(a){return new RegExp("^(("+a.join(")|(")+"))\\b")}function h(a){return a.scopes[a.scopes.length-1]}var c=b(["and","or","not","is"]),d=["as","assert","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","lambda","pass","raise","return","try","while","with","yield","in"],e=["abs","all","any","bin","bool","bytearray","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip","__import__","NotImplemented","Ellipsis","__debug__"],f={builtins:["apply","basestring","buffer","cmp","coerce","execfile","file","intern","long","raw_input","reduce","reload","unichr","unicode","xrange","False","True","None"],keywords:["exec","print"]},g={builtins:["ascii","bytes","exec","print"],keywords:["nonlocal","False","True","None","async","await"]};a.registerHelper("hintWords","python",d.concat(e)),a.defineMode("python",function(i,j){function x(a,b){if(a.sol()&&"py"==h(b).type){var c=h(b).offset;if(a.eatSpace()){var d=a.indentation();return d>c?A(a,b,"py"):c>d&&B(a,b)&&(b.errorToken=!0),null}var e=y(a,b);return c>0&&B(a,b)&&(e+=" "+k),e}return y(a,b)}function y(a,b){if(a.eatSpace())return null;var d=a.peek();if("#"==d)return a.skipToEnd(),"comment";if(a.match(/^[0-9\.]/,!1)){var e=!1;if(a.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)&&(e=!0),a.match(/^\d+\.\d*/)&&(e=!0),a.match(/^\.\d+/)&&(e=!0),e)return a.eat(/J/i),"number";var f=!1;if(a.match(/^0x[0-9a-f]+/i)&&(f=!0),a.match(/^0b[01]+/i)&&(f=!0),a.match(/^0o[0-7]+/i)&&(f=!0),a.match(/^[1-9]\d*(e[\+\-]?\d+)?/)&&(a.eat(/J/i),f=!0),a.match(/^0(?![\dx])/i)&&(f=!0),f)return a.eat(/L/i),"number"}return a.match(u)?(b.tokenize=z(a.current()),b.tokenize(a,b)):a.match(o)||a.match(n)?null:a.match(m)||a.match(p)?"operator":a.match(l)?null:a.match(v)||a.match(c)?"keyword":a.match(w)?"builtin":a.match(/^(self|cls)\b/)?"variable-2":a.match(q)?"def"==b.lastToken||"class"==b.lastToken?"def":"variable":(a.next(),k)}function z(a){function d(d,e){for(;!d.eol();)if(d.eatWhile(/[^'"\\]/),d.eat("\\")){if(d.next(),b&&d.eol())return c}else{if(d.match(a))return e.tokenize=x,c;d.eat(/['"]/)}if(b){if(j.singleLineStringErrors)return k;e.tokenize=x}return c}for(;"rub".indexOf(a.charAt(0).toLowerCase())>=0;)a=a.substr(1);var b=1==a.length,c="string";return d.isString=!0,d}function A(a,b,c){var d=0,e=null;if("py"==c)for(;"py"!=h(b).type;)b.scopes.pop();d=h(b).offset+("py"==c?i.indentUnit:r),"py"==c||a.match(/^(\s|#.*)*$/,!1)||(e=a.column()+1),b.scopes.push({offset:d,type:c,align:e})}function B(a,b){for(var c=a.indentation();h(b).offset>c;){if("py"!=h(b).type)return!0;b.scopes.pop()}return h(b).offset!=c}function C(a,b){var c=b.tokenize(a,b),d=a.current();if("."==d)return c=a.match(q,!1)?null:k,null==c&&"meta"==b.lastStyle&&(c="meta"),c;if("@"==d)return j.version&&3==parseInt(j.version,10)?a.match(q,!1)?"meta":"operator":a.match(q,!1)?"meta":k;"variable"!=c&&"builtin"!=c||"meta"!=b.lastStyle||(c="meta"),("pass"==d||"return"==d)&&(b.dedent+=1),"lambda"==d&&(b.lambda=!0),":"!=d||b.lambda||"py"!=h(b).type||A(a,b,"py");var e=1==d.length?"[({".indexOf(d):-1;if(-1!=e&&A(a,b,"])}".slice(e,e+1)),e="])}".indexOf(d),-1!=e){if(h(b).type!=d)return k;b.scopes.pop()}return b.dedent>0&&a.eol()&&"py"==h(b).type&&(b.scopes.length>1&&b.scopes.pop(),b.dedent-=1),c}var k="error",l=j.singleDelimiters||new RegExp("^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]"),m=j.doubleOperators||new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"),n=j.doubleDelimiters||new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"),o=j.tripleDelimiters||new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");if(j.version&&3==parseInt(j.version,10))var p=j.singleOperators||new RegExp("^[\\+\\-\\*/%&|\\^~<>!@]"),q=j.identifiers||new RegExp("^[_A-Za-z\xa1-\uffff][_A-Za-z0-9\xa1-\uffff]*");else var p=j.singleOperators||new RegExp("^[\\+\\-\\*/%&|\\^~<>!]"),q=j.identifiers||new RegExp("^[_A-Za-z][_A-Za-z0-9]*");var r=j.hangingIndent||i.indentUnit,s=d,t=e;if(void 0!=j.extra_keywords&&(s=s.concat(j.extra_keywords)),void 0!=j.extra_builtins&&(t=t.concat(j.extra_builtins)),j.version&&3==parseInt(j.version,10)){s=s.concat(g.keywords),t=t.concat(g.builtins);var u=new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))","i")}else{s=s.concat(f.keywords),t=t.concat(f.builtins);var u=new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))","i")}var v=b(s),w=b(t),D={startState:function(a){return{tokenize:x,scopes:[{offset:a||0,type:"py",align:null}],lastStyle:null,lastToken:null,lambda:!1,dedent:0}},token:function(a,b){var c=b.errorToken;c&&(b.errorToken=!1);var d=C(a,b);b.lastStyle=d;var e=a.current();return e&&d&&(b.lastToken=e),a.eol()&&b.lambda&&(b.lambda=!1),c?d+" "+k:d},indent:function(b,c){if(b.tokenize!=x)return b.tokenize.isString?a.Pass:0;var d=h(b),e=c&&c.charAt(0)==d.type;return null!=d.align?d.align-(e?1:0):e&&b.scopes.length>1?b.scopes[b.scopes.length-2].offset:d.offset},closeBrackets:{triples:"'\""},lineComment:"#",fold:"indent"};return D}),a.defineMIME("text/x-python","python");var i=function(a){return a.split(" ")};a.defineMIME("text/x-cython",{name:"python",extra_keywords:i("by cdef cimport cpdef ctypedef enum exceptextern gil include nogil property publicreadonly struct union DEF IF ELIF ELSE")})}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){"use strict";a.defineMode("shell",function(){function b(b,c){for(var d=c.split(" "),e=0;e<d.length;e++)a[d[e]]=b}function c(b,c){if(b.eatSpace())return null;var g=b.sol(),h=b.next();if("\\"===h)return b.next(),null;if("'"===h||'"'===h||"`"===h)return c.tokens.unshift(d(h)),f(b,c);if("#"===h)return g&&b.eat("!")?(b.skipToEnd(),"meta"):(b.skipToEnd(),"comment");if("$"===h)return c.tokens.unshift(e),f(b,c);if("+"===h||"="===h)return"operator";if("-"===h)return b.eat("-"),b.eatWhile(/\w/),"attribute";if(/\d/.test(h)&&(b.eatWhile(/\d/),b.eol()||!/\w/.test(b.peek())))return"number";b.eatWhile(/[\w-]/);var i=b.current();return"="===b.peek()&&/\w+/.test(i)?"def":a.hasOwnProperty(i)?a[i]:null}function d(a){return function(b,c){for(var d,f=!1,g=!1;null!=(d=b.next());){if(d===a&&!g){f=!0;break}if("$"===d&&!g&&"'"!==a){g=!0,b.backUp(1),c.tokens.unshift(e);break}g=!g&&"\\"===d}return(f||!g)&&c.tokens.shift(),"`"===a||")"===a?"quote":"string"}}function f(a,b){return(b.tokens[0]||c)(a,b)}var a={};b("atom","true false"),b("keyword","if then do else elif while until for in esac fi fin fil done exit set unset export function"),b("builtin","ab awk bash beep cat cc cd chown chmod chroot clear cp curl cut diff echo find gawk gcc get git grep kill killall ln ls make mkdir openssl mv nc node npm ping ps restart rm rmdir sed service sh shopt shred source sort sleep ssh start stop su sudo tee telnet top touch vi vim wall wc wget who write yes zsh");var e=function(a,b){b.tokens.length>1&&a.eat("$");var c=a.next(),e=/\w/;return"{"===c&&(e=/[^}]/),"("===c?(b.tokens[0]=d(")"),f(a,b)):(/\d/.test(c)||(a.eatWhile(e),a.eat("}")),b.tokens.shift(),"def")};return{startState:function(){return{tokens:[]}},token:function(a,b){return f(a,b)},lineComment:"#",fold:"brace"}}),a.defineMIME("text/x-sh","shell")}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){"use strict";a.defineMode("xml",function(b,c){function k(a,b){function c(c){return b.tokenize=c,c(a,b)}var d=a.next();if("<"==d)return a.eat("!")?a.eat("[")?a.match("CDATA[")?c(n("atom","]]>")):null:a.match("--")?c(n("comment","-->")):a.match("DOCTYPE",!0,!0)?(a.eatWhile(/[\w\._\-]/),c(o(1))):null:a.eat("?")?(a.eatWhile(/[\w\._\-]/),b.tokenize=n("meta","?>"),"meta"):(i=a.eat("/")?"closeTag":"openTag",b.tokenize=l,"tag bracket");if("&"==d){var e;return e=a.eat("#")?a.eat("x")?a.eatWhile(/[a-fA-F\d]/)&&a.eat(";"):a.eatWhile(/[\d]/)&&a.eat(";"):a.eatWhile(/[\w\.\-:]/)&&a.eat(";"),e?"atom":"error"}return a.eatWhile(/[^&<]/),null}function l(a,b){var c=a.next();if(">"==c||"/"==c&&a.eat(">"))return b.tokenize=k,i=">"==c?"endTag":"selfcloseTag","tag bracket";if("="==c)return i="equals",null;if("<"==c){b.tokenize=k,b.state=s,b.tagName=b.tagStart=null;var d=b.tokenize(a,b);return d?d+" tag error":"tag error"}return/[\'\"]/.test(c)?(b.tokenize=m(c),b.stringStartCol=a.column(),b.tokenize(a,b)):(a.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/),"word")}function m(a){var b=function(b,c){for(;!b.eol();)if(b.next()==a){c.tokenize=l;break}return"string"};return b.isInAttribute=!0,b}function n(a,b){return function(c,d){for(;!c.eol();){if(c.match(b)){d.tokenize=k;break}c.next()}return a}}function o(a){return function(b,c){for(var d;null!=(d=b.next());){if("<"==d)return c.tokenize=o(a+1),c.tokenize(b,c);if(">"==d){if(1==a){c.tokenize=k;break}return c.tokenize=o(a-1),c.tokenize(b,c)}}return"meta"}}function p(a,b,c){this.prev=a.context,this.tagName=b,this.indent=a.indented,this.startOfLine=c,(g.doNotIndent.hasOwnProperty(b)||a.context&&a.context.noIndent)&&(this.noIndent=!0)}function q(a){a.context&&(a.context=a.context.prev)}function r(a,b){for(var c;;){if(!a.context)return;if(c=a.context.tagName,!g.contextGrabbers.hasOwnProperty(c)||!g.contextGrabbers[c].hasOwnProperty(b))return;q(a)}}function s(a,b,c){return"openTag"==a?(c.tagStart=b.column(),t):"closeTag"==a?u:s}function t(a,b,c){return"word"==a?(c.tagName=b.current(),j="tag",x):(j="error",t)}function u(a,b,c){if("word"==a){var d=b.current();return c.context&&c.context.tagName!=d&&g.implicitlyClosed.hasOwnProperty(c.context.tagName)&&q(c),c.context&&c.context.tagName==d?(j="tag",v):(j="tag error",w)}return j="error",w}function v(a,b,c){return"endTag"!=a?(j="error",v):(q(c),s)}function w(a,b,c){return j="error",v(a,b,c)}function x(a,b,c){if("word"==a)return j="attribute",y;if("endTag"==a||"selfcloseTag"==a){var d=c.tagName,e=c.tagStart;return c.tagName=c.tagStart=null,"selfcloseTag"==a||g.autoSelfClosers.hasOwnProperty(d)?r(c,d):(r(c,d),c.context=new p(c,d,e==c.indented)),s}return j="error",x}function y(a,b,c){return"equals"==a?z:(g.allowMissing||(j="error"),x(a,b,c))}function z(a,b,c){return"string"==a?A:"word"==a&&g.allowUnquoted?(j="string",x):(j="error",x(a,b,c))}function A(a,b,c){return"string"==a?A:x(a,b,c)}var d=b.indentUnit,e=c.multilineTagIndentFactor||1,f=c.multilineTagIndentPastTag;null==f&&(f=!0);var i,j,g=c.htmlMode?{autoSelfClosers:{area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0,menuitem:!0},implicitlyClosed:{dd:!0,li:!0,optgroup:!0,option:!0,p:!0,rp:!0,rt:!0,tbody:!0,td:!0,tfoot:!0,th:!0,tr:!0},contextGrabbers:{dd:{dd:!0,dt:!0},dt:{dd:!0,dt:!0},li:{li:!0},option:{option:!0,optgroup:!0},optgroup:{optgroup:!0},p:{address:!0,article:!0,aside:!0,blockquote:!0,dir:!0,div:!0,dl:!0,fieldset:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,menu:!0,nav:!0,ol:!0,p:!0,pre:!0,section:!0,table:!0,ul:!0},rp:{rp:!0,rt:!0},rt:{rp:!0,rt:!0},tbody:{tbody:!0,tfoot:!0},td:{td:!0,th:!0},tfoot:{tbody:!0},th:{td:!0,th:!0},thead:{tbody:!0,tfoot:!0},tr:{tr:!0}},doNotIndent:{pre:!0},allowUnquoted:!0,allowMissing:!0,caseFold:!0}:{autoSelfClosers:{},implicitlyClosed:{},contextGrabbers:{},doNotIndent:{},allowUnquoted:!1,allowMissing:!1,caseFold:!1},h=c.alignCDATA;return k.isInText=!0,{startState:function(){return{tokenize:k,state:s,indented:0,tagName:null,tagStart:null,context:null}},token:function(a,b){if(!b.tagName&&a.sol()&&(b.indented=a.indentation()),a.eatSpace())return null;i=null;var c=b.tokenize(a,b);return(c||i)&&"comment"!=c&&(j=null,b.state=b.state(i||c,a,b),j&&(c="error"==j?c+" error":j)),c},indent:function(b,c,i){var j=b.context;if(b.tokenize.isInAttribute)return b.tagStart==b.indented?b.stringStartCol+1:b.indented+d;if(j&&j.noIndent)return a.Pass;if(b.tokenize!=l&&b.tokenize!=k)return i?i.match(/^(\s*)/)[0].length:0;if(b.tagName)return f?b.tagStart+b.tagName.length+2:b.tagStart+d*e;if(h&&/<!\[CDATA\[/.test(c))return 0;var m=c&&/^<(\/)?([\w_:\.-]*)/.exec(c);if(m&&m[1])for(;j;){if(j.tagName==m[2]){j=j.prev;break}if(!g.implicitlyClosed.hasOwnProperty(j.tagName))break;j=j.prev}else if(m)for(;j;){var n=g.contextGrabbers[j.tagName];if(!n||!n.hasOwnProperty(m[2]))break;j=j.prev}for(;j&&!j.startOfLine;)j=j.prev;return j?j.indent+d:0},electricInput:/<\/[\s\w:]+>$/,blockCommentStart:"<!--",blockCommentEnd:"-->",configuration:c.htmlMode?"html":"xml",helperType:c.htmlMode?"html":"xml"}}),a.defineMIME("text/xml","xml"),a.defineMIME("application/xml","xml"),a.mimeModes.hasOwnProperty("text/html")||a.defineMIME("text/html",{name:"xml",htmlMode:!0})}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){"use strict";function d(a){for(var d=0;d<a.state.activeLines.length;d++)a.removeLineClass(a.state.activeLines[d],"wrap",b),a.removeLineClass(a.state.activeLines[d],"background",c)}function e(a,b){if(a.length!=b.length)return!1;for(var c=0;c<a.length;c++)if(a[c]!=b[c])return!1;return!0}function f(a,f){for(var g=[],h=0;h<f.length;h++){var i=f[h];if(i.empty()){var j=a.getLineHandleVisualStart(i.head.line);g[g.length-1]!=j&&g.push(j)}}e(a.state.activeLines,g)||a.operation(function(){d(a);for(var e=0;e<g.length;e++)a.addLineClass(g[e],"wrap",b),a.addLineClass(g[e],"background",c);a.state.activeLines=g})}function g(a,b){f(a,b.ranges)}var b="CodeMirror-activeline",c="CodeMirror-activeline-background";a.defineOption("styleActiveLine",!1,function(b,c,e){var h=e&&e!=a.Init;c&&!h?(b.state.activeLines=[],f(b,b.listSelections()),b.on("beforeSelectionChange",g)):!c&&h&&(b.off("beforeSelectionChange",g),d(b),delete b.state.activeLines)})}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){"use strict";a.registerHelper("fold","brace",function(b,c){function h(f){for(var h=c.ch,i=0;;){var j=0>=h?-1:e.lastIndexOf(f,h-1);if(-1!=j){if(1==i&&j<c.ch)break;if(g=b.getTokenTypeAt(a.Pos(d,j+1)),!/^(comment|string)/.test(g))return j+1;h=j-1}else{if(1==i)break;i=1,h=e.length}}}var f,g,d=c.line,e=b.getLine(d),i="{",j="}",f=h("{");if(null==f&&(i="[",j="]",f=h("[")),null!=f){var m,n,k=1,l=b.lastLine();a:for(var o=d;l>=o;++o)for(var p=b.getLine(o),q=o==d?f:0;;){var r=p.indexOf(i,q),s=p.indexOf(j,q);if(0>r&&(r=p.length),0>s&&(s=p.length),q=Math.min(r,s),q==p.length)break;if(b.getTokenTypeAt(a.Pos(o,q+1))==g)if(q==r)++k;else if(!--k){m=o,n=q;break a}++q}if(null!=m&&(d!=m||n!=f))return{from:a.Pos(d,f),to:a.Pos(m,n)}}}),a.registerHelper("fold","import",function(b,c){function d(c){if(c<b.firstLine()||c>b.lastLine())return null;var d=b.getTokenAt(a.Pos(c,1));if(/\S/.test(d.string)||(d=b.getTokenAt(a.Pos(c,d.end+1))),"keyword"!=d.type||"import"!=d.string)return null;for(var e=c,f=Math.min(b.lastLine(),c+10);f>=e;++e){var g=b.getLine(e),h=g.indexOf(";");if(-1!=h)return{startCh:d.end,end:a.Pos(e,h)}}}var f,c=c.line,e=d(c);if(!e||d(c-1)||(f=d(c-2))&&f.end.line==c-1)return null;for(var g=e.end;;){var h=d(g.line+1);if(null==h)break;g=h.end}return{from:b.clipPos(a.Pos(c,e.startCh+1)),to:g}}),a.registerHelper("fold","include",function(b,c){function d(c){if(c<b.firstLine()||c>b.lastLine())return null;var d=b.getTokenAt(a.Pos(c,1));return/\S/.test(d.string)||(d=b.getTokenAt(a.Pos(c,d.end+1))),"meta"==d.type&&"#include"==d.string.slice(0,8)?d.start+8:void 0}var c=c.line,e=d(c);if(null==e||null!=d(c-1))return null;for(var f=c;;){var g=d(f+1);if(null==g)break;++f}return{from:a.Pos(c,e+1),to:b.clipPos(a.Pos(f))}})}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){function d(a,c){return"pairs"==c&&"string"==typeof a?a:"object"==typeof a&&null!=a[c]?a[c]:b[c]}function h(a){return function(b){return l(b,a)}}function i(a){var b=a.state.closeBrackets;if(!b)return null;var c=a.getModeAt(a.getCursor());return c.closeBrackets||b}function j(b){var e=i(b);if(!e||b.getOption("disableInput"))return a.Pass;for(var f=d(e,"pairs"),g=b.listSelections(),h=0;h<g.length;h++){if(!g[h].empty())return a.Pass;var j=n(b,g[h].head);if(!j||f.indexOf(j)%2!=0)return a.Pass}for(var h=g.length-1;h>=0;h--){var k=g[h].head;b.replaceRange("",c(k.line,k.ch-1),c(k.line,k.ch+1))}}function k(b){var c=i(b),e=c&&d(c,"explode");if(!e||b.getOption("disableInput"))return a.Pass;for(var f=b.listSelections(),g=0;g<f.length;g++){if(!f[g].empty())return a.Pass;var h=n(b,f[g].head);if(!h||e.indexOf(h)%2!=0)return a.Pass}b.operation(function(){b.replaceSelection("\n\n",null),b.execCommand("goCharLeft"),f=b.listSelections();for(var a=0;a<f.length;a++){var c=f[a].head.line;b.indentLine(c,null,!0),b.indentLine(c+1,null,!0)}})}function l(b,e){var f=i(b);if(!f||b.getOption("disableInput"))return a.Pass;var g=d(f,"pairs"),h=g.indexOf(e);if(-1==h)return a.Pass;for(var p,q,j=d(f,"triples"),k=g.charAt(h+1)==e,l=b.listSelections(),n=h%2==0,r=0;r<l.length;r++){var u,s=l[r],t=s.head,q=b.getRange(t,c(t.line,t.ch+1));if(n&&!s.empty())u="surround";else if(!k&&n||q!=e)if(k&&t.ch>1&&j.indexOf(e)>=0&&b.getRange(c(t.line,t.ch-2),t)==e+e&&(t.ch<=2||b.getRange(c(t.line,t.ch-3),c(t.line,t.ch-2))!=e))u="addFour";else if(k){if(a.isWordChar(q)||!o(b,t,e))return a.Pass;u="both"}else{if(!n||b.getLine(t.line).length!=t.ch&&!m(q,g)&&!/\s/.test(q))return a.Pass;u="both"}else u=j.indexOf(e)>=0&&b.getRange(t,c(t.line,t.ch+3))==e+e+e?"skipThree":"skip";if(p){if(p!=u)return a.Pass}else p=u}var v=h%2?g.charAt(h-1):e,w=h%2?e:g.charAt(h+1);b.operation(function(){if("skip"==p)b.execCommand("goCharRight");else if("skipThree"==p)for(var a=0;3>a;a++)b.execCommand("goCharRight");else if("surround"==p){for(var c=b.getSelections(),a=0;a<c.length;a++)c[a]=v+c[a]+w;b.replaceSelections(c,"around")}else"both"==p?(b.replaceSelection(v+w,null),b.triggerElectric(v+w),b.execCommand("goCharLeft")):"addFour"==p&&(b.replaceSelection(v+v+v+v,"before"),b.execCommand("goCharRight"))})}function m(a,b){var c=b.lastIndexOf(a);return c>-1&&c%2==1}function n(a,b){var d=a.getRange(c(b.line,b.ch-1),c(b.line,b.ch+1));return 2==d.length?d:null}function o(b,c,d){var e=b.getLine(c.line),f=b.getTokenAt(c);if(/\bstring2?\b/.test(f.type))return!1;var g=new a.StringStream(e.slice(0,c.ch)+d+e.slice(c.ch),4);for(g.pos=g.start=f.start;;){var h=b.getMode().token(g,f.state);if(g.pos>=c.ch+1)return/\bstring2?\b/.test(h);g.start=g.pos}}var b={pairs:"()[]{}''\"\"",triples:"",explode:"[]{}"},c=a.Pos;a.defineOption("autoCloseBrackets",!1,function(b,c,d){d&&d!=a.Init&&(b.removeKeyMap(f),b.state.closeBrackets=null),c&&(b.state.closeBrackets=c,b.addKeyMap(f))});for(var e=b.pairs+"`",f={Backspace:j,Enter:k},g=0;g<e.length;g++)f["'"+e.charAt(g)+"'"]=h(e.charAt(g))}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror"),require("../fold/xml-fold")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","../fold/xml-fold"],a):a(CodeMirror)}(function(a){function d(d){if(d.getOption("disableInput"))return a.Pass;for(var e=d.listSelections(),f=[],i=0;i<e.length;i++){if(!e[i].empty())return a.Pass;var j=e[i].head,k=d.getTokenAt(j),l=a.innerMode(d.getMode(),k.state),m=l.state;if("xml"!=l.mode.name||!m.tagName)return a.Pass;var n=d.getOption("autoCloseTags"),o="html"==l.mode.configuration,p="object"==typeof n&&n.dontCloseTags||o&&b,q="object"==typeof n&&n.indentTags||o&&c,r=m.tagName;k.end>j.ch&&(r=r.slice(0,r.length-k.end+j.ch));var s=r.toLowerCase();if(!r||"string"==k.type&&(k.end!=j.ch||!/[\"\']/.test(k.string.charAt(k.string.length-1))||1==k.string.length)||"tag"==k.type&&"closeTag"==m.type||k.string.indexOf("/")==k.string.length-1||p&&g(p,s)>-1||h(d,r,j,m,!0))return a.Pass;var t=q&&g(q,s)>-1;f[i]={indent:t,text:">"+(t?"\n\n":"")+"</"+r+">",newPos:t?a.Pos(j.line+1,0):a.Pos(j.line,j.ch+1)}}for(var i=e.length-1;i>=0;i--){var u=f[i];d.replaceRange(u.text,e[i].head,e[i].anchor,"+insert");var v=d.listSelections().slice(0);v[i]={head:u.newPos,anchor:u.newPos},d.setSelections(v),u.indent&&(d.indentLine(u.newPos.line,null,!0),d.indentLine(u.newPos.line+1,null,!0))}}function e(b,c){for(var d=b.listSelections(),e=[],f=c?"/":"</",g=0;g<d.length;g++){if(!d[g].empty())return a.Pass;var i=d[g].head,j=b.getTokenAt(i),k=a.innerMode(b.getMode(),j.state),l=k.state;if(c&&("string"==j.type||"<"!=j.string.charAt(0)||j.start!=i.ch-1))return a.Pass;var m;if("xml"!=k.mode.name)if("htmlmixed"==b.getMode().name&&"javascript"==k.mode.name)m=f+"script";else{if("htmlmixed"!=b.getMode().name||"css"!=k.mode.name)return a.Pass;m=f+"style"}else{if(!l.context||!l.context.tagName||h(b,l.context.tagName,i,l))return a.Pass;m=f+l.context.tagName;
+}">"!=b.getLine(i.line).charAt(j.end)&&(m+=">"),e[g]=m}b.replaceSelections(e),d=b.listSelections();for(var g=0;g<d.length;g++)(g==d.length-1||d[g].head.line<d[g+1].head.line)&&b.indentLine(d[g].head.line)}function f(b){return b.getOption("disableInput")?a.Pass:e(b,!0)}function g(a,b){if(a.indexOf)return a.indexOf(b);for(var c=0,d=a.length;d>c;++c)if(a[c]==b)return c;return-1}function h(b,c,d,e,f){if(!a.scanForClosingTag)return!1;var g=Math.min(b.lastLine()+1,d.line+500),h=a.scanForClosingTag(b,d,null,g);if(!h||h.tag!=c)return!1;for(var i=e.context,j=f?1:0;i&&i.tagName==c;i=i.prev)++j;d=h.to;for(var k=1;j>k;k++){var l=a.scanForClosingTag(b,d,null,g);if(!l||l.tag!=c)return!1;d=l.to}return!0}a.defineOption("autoCloseTags",!1,function(b,c,e){if(e!=a.Init&&e&&b.removeKeyMap("autoCloseTags"),c){var g={name:"autoCloseTags"};("object"!=typeof c||c.whenClosing)&&(g["'/'"]=function(a){return f(a)}),("object"!=typeof c||c.whenOpening)&&(g["'>'"]=function(a){return d(a)}),b.addKeyMap(g)}});var b=["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"],c=["applet","blockquote","body","button","div","dl","fieldset","form","frameset","h1","h2","h3","h4","h5","h6","head","html","iframe","layer","legend","object","ol","p","select","table","ul"];a.commands.closeTag=function(a){return e(a)}}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){"use strict";function b(b,d,f,g){function j(a){var c=h(b,d);if(!c||c.to.line-c.from.line<i)return null;for(var e=b.findMarksAt(c.from),f=0;f<e.length;++f)if(e[f].__isFold&&"fold"!==g){if(!a)return null;c.cleared=!0,e[f].clear()}return c}if(f&&f.call){var h=f;f=null}else var h=e(b,f,"rangeFinder");"number"==typeof d&&(d=a.Pos(d,0));var i=e(b,f,"minFoldSize"),k=j(!0);if(e(b,f,"scanUp"))for(;!k&&d.line>b.firstLine();)d=a.Pos(d.line-1,0),k=j(!1);if(k&&!k.cleared&&"unfold"!==g){var l=c(b,f);a.on(l,"mousedown",function(b){m.clear(),a.e_preventDefault(b)});var m=b.markText(k.from,k.to,{replacedWith:l,clearOnEnter:!0,__isFold:!0});m.on("clear",function(c,d){a.signal(b,"unfold",b,c,d)}),a.signal(b,"fold",b,k.from,k.to)}}function c(a,b){var c=e(a,b,"widget");if("string"==typeof c){var d=document.createTextNode(c);c=document.createElement("span"),c.appendChild(d),c.className="CodeMirror-foldmarker"}return c}function e(a,b,c){if(b&&void 0!==b[c])return b[c];var e=a.options.foldOptions;return e&&void 0!==e[c]?e[c]:d[c]}a.newFoldFunction=function(a,c){return function(d,e){b(d,e,{rangeFinder:a,widget:c})}},a.defineExtension("foldCode",function(a,c,d){b(this,a,c,d)}),a.defineExtension("isFolded",function(a){for(var b=this.findMarksAt(a),c=0;c<b.length;++c)if(b[c].__isFold)return!0}),a.commands.toggleFold=function(a){a.foldCode(a.getCursor())},a.commands.fold=function(a){a.foldCode(a.getCursor(),null,"fold")},a.commands.unfold=function(a){a.foldCode(a.getCursor(),null,"unfold")},a.commands.foldAll=function(b){b.operation(function(){for(var c=b.firstLine(),d=b.lastLine();d>=c;c++)b.foldCode(a.Pos(c,0),null,"fold")})},a.commands.unfoldAll=function(b){b.operation(function(){for(var c=b.firstLine(),d=b.lastLine();d>=c;c++)b.foldCode(a.Pos(c,0),null,"unfold")})},a.registerHelper("fold","combine",function(){var a=Array.prototype.slice.call(arguments,0);return function(b,c){for(var d=0;d<a.length;++d){var e=a[d](b,c);if(e)return e}}}),a.registerHelper("fold","auto",function(a,b){for(var c=a.getHelpers(b,"fold"),d=0;d<c.length;d++){var e=c[d](a,b);if(e)return e}});var d={rangeFinder:a.fold.auto,widget:"\u2194",minFoldSize:0,scanUp:!1};a.defineOption("foldOptions",null),a.defineExtension("foldOption",function(a,b){return e(this,a,b)})}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror"),require("./foldcode")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","./foldcode"],a):a(CodeMirror)}(function(a){"use strict";function c(a){this.options=a,this.from=this.to=0}function d(a){return a===!0&&(a={}),null==a.gutter&&(a.gutter="CodeMirror-foldgutter"),null==a.indicatorOpen&&(a.indicatorOpen="CodeMirror-foldgutter-open"),null==a.indicatorFolded&&(a.indicatorFolded="CodeMirror-foldgutter-folded"),a}function e(a,c){for(var d=a.findMarksAt(b(c)),e=0;e<d.length;++e)if(d[e].__isFold&&d[e].find().from.line==c)return d[e]}function f(a){if("string"==typeof a){var b=document.createElement("div");return b.className=a+" CodeMirror-guttermarker-subtle",b}return a.cloneNode(!0)}function g(a,c,d){var g=a.state.foldGutter.options,h=c,i=a.foldOption(g,"minFoldSize"),j=a.foldOption(g,"rangeFinder");a.eachLine(c,d,function(c){var d=null;if(e(a,h))d=f(g.indicatorFolded);else{var k=b(h,0),l=j&&j(a,k);l&&l.to.line-l.from.line>=i&&(d=f(g.indicatorOpen))}a.setGutterMarker(c,g.gutter,d),++h})}function h(a){var b=a.getViewport(),c=a.state.foldGutter;c&&(a.operation(function(){g(a,b.from,b.to)}),c.from=b.from,c.to=b.to)}function i(a,c,d){var f=a.state.foldGutter;if(f){var g=f.options;if(d==g.gutter){var h=e(a,c);h?h.clear():a.foldCode(b(c,0),g.rangeFinder)}}}function j(a){var b=a.state.foldGutter;if(b){var c=b.options;b.from=b.to=0,clearTimeout(b.changeUpdate),b.changeUpdate=setTimeout(function(){h(a)},c.foldOnChangeTimeSpan||600)}}function k(a){var b=a.state.foldGutter;if(b){var c=b.options;clearTimeout(b.changeUpdate),b.changeUpdate=setTimeout(function(){var c=a.getViewport();b.from==b.to||c.from-b.to>20||b.from-c.to>20?h(a):a.operation(function(){c.from<b.from&&(g(a,c.from,b.from),b.from=c.from),c.to>b.to&&(g(a,b.to,c.to),b.to=c.to)})},c.updateViewportTimeSpan||400)}}function l(a,b){var c=a.state.foldGutter;if(c){var d=b.line;d>=c.from&&d<c.to&&g(a,d,d+1)}}a.defineOption("foldGutter",!1,function(b,e,f){f&&f!=a.Init&&(b.clearGutter(b.state.foldGutter.options.gutter),b.state.foldGutter=null,b.off("gutterClick",i),b.off("change",j),b.off("viewportChange",k),b.off("fold",l),b.off("unfold",l),b.off("swapDoc",h)),e&&(b.state.foldGutter=new c(d(e)),h(b),b.on("gutterClick",i),b.on("change",j),b.on("viewportChange",k),b.on("fold",l),b.on("unfold",l),b.on("swapDoc",h))});var b=a.Pos}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){"use strict";a.registerHelper("fold","indent",function(b,c){var d=b.getOption("tabSize"),e=b.getLine(c.line);if(/\S/.test(e)){for(var f=function(b){return a.countColumn(b,null,d)},g=f(e),h=null,i=c.line+1,j=b.lastLine();j>=i;++i){var k=b.getLine(i),l=f(k);if(l>g)h=i;else if(/\S/.test(k))break}return h?{from:a.Pos(c.line,e.length),to:a.Pos(h,b.getLine(h).length)}:void 0}})}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){"use strict";function f(a){"object"==typeof a&&(this.minChars=a.minChars,this.style=a.style,this.showToken=a.showToken,this.delay=a.delay,this.wordsOnly=a.wordsOnly),null==this.style&&(this.style=c),null==this.minChars&&(this.minChars=b),null==this.delay&&(this.delay=d),null==this.wordsOnly&&(this.wordsOnly=e),this.overlay=this.timeout=null}function g(a){var b=a.state.matchHighlighter;clearTimeout(b.timeout),b.timeout=setTimeout(function(){h(a)},b.delay)}function h(a){a.operation(function(){var b=a.state.matchHighlighter;if(b.overlay&&(a.removeOverlay(b.overlay),b.overlay=null),!a.somethingSelected()&&b.showToken){for(var c=b.showToken===!0?/[\w$]/:b.showToken,d=a.getCursor(),e=a.getLine(d.line),f=d.ch,g=f;f&&c.test(e.charAt(f-1));)--f;for(;g<e.length&&c.test(e.charAt(g));)++g;return void(g>f&&a.addOverlay(b.overlay=k(e.slice(f,g),c,b.style)))}var h=a.getCursor("from"),j=a.getCursor("to");if(h.line==j.line&&(!b.wordsOnly||i(a,h,j))){var l=a.getRange(h,j).replace(/^\s+|\s+$/g,"");l.length>=b.minChars&&a.addOverlay(b.overlay=k(l,!1,b.style))}})}function i(a,b,c){var d=a.getRange(b,c);if(null!==d.match(/^\w+$/)){if(b.ch>0){var e={line:b.line,ch:b.ch-1},f=a.getRange(e,b);if(null===f.match(/\W/))return!1}if(c.ch<a.getLine(b.line).length){var e={line:c.line,ch:c.ch+1},f=a.getRange(c,e);if(null===f.match(/\W/))return!1}return!0}return!1}function j(a,b){return!(a.start&&b.test(a.string.charAt(a.start-1))||a.pos!=a.string.length&&b.test(a.string.charAt(a.pos)))}function k(a,b,c){return{token:function(d){return!d.match(a)||b&&!j(d,b)?(d.next(),void(d.skipTo(a.charAt(0))||d.skipToEnd())):c}}}var b=2,c="matchhighlight",d=100,e=!1;a.defineOption("highlightSelectionMatches",!1,function(b,c,d){if(d&&d!=a.Init){var e=b.state.matchHighlighter.overlay;e&&b.removeOverlay(e),clearTimeout(b.state.matchHighlighter.timeout),b.state.matchHighlighter=null,b.off("cursorActivity",g)}c&&(b.state.matchHighlighter=new f(c),h(b),b.on("cursorActivity",g))})}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){function e(a,b,e,g){var h=a.getLineHandle(b.line),i=b.ch-1,j=i>=0&&d[h.text.charAt(i)]||d[h.text.charAt(++i)];if(!j)return null;var k=">"==j.charAt(1)?1:-1;if(e&&k>0!=(i==b.ch))return null;var l=a.getTokenTypeAt(c(b.line,i+1)),m=f(a,c(b.line,i+(k>0?1:0)),k,l||null,g);return null==m?null:{from:c(b.line,i),to:m&&m.pos,match:m&&m.ch==j.charAt(0),forward:k>0}}function f(a,b,e,f,g){for(var h=g&&g.maxScanLineLength||1e4,i=g&&g.maxScanLines||1e3,j=[],k=g&&g.bracketRegex?g.bracketRegex:/[(){}[\]]/,l=e>0?Math.min(b.line+i,a.lastLine()+1):Math.max(a.firstLine()-1,b.line-i),m=b.line;m!=l;m+=e){var n=a.getLine(m);if(n){var o=e>0?0:n.length-1,p=e>0?n.length:-1;if(!(n.length>h))for(m==b.line&&(o=b.ch-(0>e?1:0));o!=p;o+=e){var q=n.charAt(o);if(k.test(q)&&(void 0===f||a.getTokenTypeAt(c(m,o+1))==f)){var r=d[q];if(">"==r.charAt(1)==e>0)j.push(q);else{if(!j.length)return{pos:c(m,o),ch:q};j.pop()}}}}}return m-e==(e>0?a.lastLine():a.firstLine())?!1:null}function g(a,d,f){for(var g=a.state.matchBrackets.maxHighlightLineLength||1e3,h=[],i=a.listSelections(),j=0;j<i.length;j++){var k=i[j].empty()&&e(a,i[j].head,!1,f);if(k&&a.getLine(k.from.line).length<=g){var l=k.match?"CodeMirror-matchingbracket":"CodeMirror-nonmatchingbracket";h.push(a.markText(k.from,c(k.from.line,k.from.ch+1),{className:l})),k.to&&a.getLine(k.to.line).length<=g&&h.push(a.markText(k.to,c(k.to.line,k.to.ch+1),{className:l}))}}if(h.length){b&&a.state.focused&&a.focus();var m=function(){a.operation(function(){for(var a=0;a<h.length;a++)h[a].clear()})};if(!d)return m;setTimeout(m,800)}}function i(a){a.operation(function(){h&&(h(),h=null),h=g(a,!1,a.state.matchBrackets)})}var b=/MSIE \d/.test(navigator.userAgent)&&(null==document.documentMode||document.documentMode<8),c=a.Pos,d={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"},h=null;a.defineOption("matchBrackets",!1,function(b,c,d){d&&d!=a.Init&&b.off("cursorActivity",i),c&&(b.state.matchBrackets="object"==typeof c?c:{},b.on("cursorActivity",i))}),a.defineExtension("matchBrackets",function(){g(this,!0)}),a.defineExtension("findMatchingBracket",function(a,b,c){return e(this,a,b,c)}),a.defineExtension("scanForBracket",function(a,b,c,d){return f(this,a,b,c,d)})}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror"),require("../fold/xml-fold")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","../fold/xml-fold"],a):a(CodeMirror)}(function(a){"use strict";function b(a){a.state.tagHit&&a.state.tagHit.clear(),a.state.tagOther&&a.state.tagOther.clear(),a.state.tagHit=a.state.tagOther=null}function c(c){c.state.failedTagMatch=!1,c.operation(function(){if(b(c),!c.somethingSelected()){var d=c.getCursor(),e=c.getViewport();e.from=Math.min(e.from,d.line),e.to=Math.max(d.line+1,e.to);var f=a.findMatchingTag(c,d,e);if(f){if(c.state.matchBothTags){var g="open"==f.at?f.open:f.close;g&&(c.state.tagHit=c.markText(g.from,g.to,{className:"CodeMirror-matchingtag"}))}var h="close"==f.at?f.open:f.close;h?c.state.tagOther=c.markText(h.from,h.to,{className:"CodeMirror-matchingtag"}):c.state.failedTagMatch=!0}}})}function d(a){a.state.failedTagMatch&&c(a)}a.defineOption("matchTags",!1,function(e,f,g){g&&g!=a.Init&&(e.off("cursorActivity",c),e.off("viewportChange",d),b(e)),f&&(e.state.matchBothTags="object"==typeof f&&f.bothTags,e.on("cursorActivity",c),e.on("viewportChange",d),c(e))}),a.commands.toMatchingTag=function(b){var c=a.findMatchingTag(b,b.getCursor());if(c){var d="close"==c.at?c.open:c.close;d&&b.extendSelection(d.to,d.from)}}}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror"),require("./searchcursor"),require("../dialog/dialog")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","./searchcursor","../dialog/dialog"],a):a(CodeMirror)}(function(a){"use strict";function b(a,b){return"string"==typeof a?a=new RegExp(a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),b?"gi":"g"):a.global||(a=new RegExp(a.source,a.ignoreCase?"gi":"g")),{token:function(b){a.lastIndex=b.pos;var c=a.exec(b.string);return c&&c.index==b.pos?(b.pos+=c[0].length,"searching"):void(c?b.pos=c.index:b.skipToEnd())}}}function c(){this.posFrom=this.posTo=this.lastQuery=this.query=null,this.overlay=null}function d(a){return a.state.search||(a.state.search=new c)}function e(a){return"string"==typeof a&&a==a.toLowerCase()}function f(a,b,c){return a.getSearchCursor(b,c,e(b))}function g(a,b,c,d){a.openDialog(b,d,{value:c,selectValueOnOpen:!0,closeOnEnter:!1,onClose:function(){p(a)}})}function h(a,b,c,d,e){a.openDialog?a.openDialog(b,e,{value:d,selectValueOnOpen:!0}):e(prompt(c,d))}function i(a,b,c,d){a.openConfirm?a.openConfirm(b,d):confirm(c)&&d[0]()}function j(a){return a.replace(/\\(.)/g,function(a,b){return"n"==b?"\n":"r"==b?"\r":b})}function k(a){var b=a.match(/^\/(.*)\/([a-z]*)$/);if(b)try{a=new RegExp(b[1],-1==b[2].indexOf("i")?"":"i")}catch(c){}else a=j(a);return("string"==typeof a?""==a:a.test(""))&&(a=/x^/),a}function m(a,c,d){c.queryText=d,c.query=k(d),a.removeOverlay(c.overlay,e(c.query)),c.overlay=b(c.query,e(c.query)),a.addOverlay(c.overlay),a.showMatchesOnScrollbar&&(c.annotate&&(c.annotate.clear(),c.annotate=null),c.annotate=a.showMatchesOnScrollbar(c.query,e(c.query)))}function n(b,c,e){var f=d(b);if(f.query)return o(b,c);var i=b.getSelection()||f.lastQuery;e&&b.openDialog?g(b,l,i,function(c,d){a.e_stop(d),c&&(c!=f.queryText&&m(b,f,c),o(b,d.shiftKey))}):h(b,l,"Search for:",i,function(a){a&&!f.query&&b.operation(function(){m(b,f,a),f.posFrom=f.posTo=b.getCursor(),o(b,c)})})}function o(b,c){b.operation(function(){var e=d(b),g=f(b,e.query,c?e.posFrom:e.posTo);(g.find(c)||(g=f(b,e.query,c?a.Pos(b.lastLine()):a.Pos(b.firstLine(),0)),g.find(c)))&&(b.setSelection(g.from(),g.to()),b.scrollIntoView({from:g.from(),to:g.to()},20),e.posFrom=g.from(),e.posTo=g.to())})}function p(a){a.operation(function(){var b=d(a);b.lastQuery=b.query,b.query&&(b.query=b.queryText=null,a.removeOverlay(b.overlay),b.annotate&&(b.annotate.clear(),b.annotate=null))})}function t(a,b){if(!a.getOption("readOnly")){var c=a.getSelection()||d(a).lastQuery;h(a,q,"Replace:",c,function(c){c&&(c=k(c),h(a,r,"Replace with:","",function(d){if(d=j(d),b)a.operation(function(){for(var b=f(a,c);b.findNext();)if("string"!=typeof c){var e=a.getRange(b.from(),b.to()).match(c);b.replace(d.replace(/\$(\d)/g,function(a,b){return e[b]}))}else b.replace(d)});else{p(a);var e=f(a,c,a.getCursor()),g=function(){var d,b=e.from();!(d=e.findNext())&&(e=f(a,c),!(d=e.findNext())||b&&e.from().line==b.line&&e.from().ch==b.ch)||(a.setSelection(e.from(),e.to()),a.scrollIntoView({from:e.from(),to:e.to()}),i(a,s,"Replace?",[function(){h(d)},g]))},h=function(a){e.replace("string"==typeof c?d:d.replace(/\$(\d)/g,function(b,c){return a[c]})),g()};g()}}))})}}var l='Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>',q='Replace: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>',r='With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>',s="Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";a.commands.find=function(a){p(a),n(a)},a.commands.findPersistent=function(a){p(a),n(a,!1,!0)},a.commands.findNext=n,a.commands.findPrev=function(a){n(a,!0)},a.commands.clearSearch=p,a.commands.replace=t,a.commands.replaceAll=function(a){t(a,!0)}}),function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){"use strict";function c(a,b){return a.line-b.line||a.ch-b.ch}function g(a,b,c,d){this.line=b,this.ch=c,this.cm=a,this.text=a.getLine(b),this.min=d?d.from:a.firstLine(),this.max=d?d.to-1:a.lastLine()}function h(a,c){var d=a.cm.getTokenTypeAt(b(a.line,c));return d&&/\btag\b/.test(d)}function i(a){return a.line>=a.max?void 0:(a.ch=0,a.text=a.cm.getLine(++a.line),!0)}function j(a){return a.line<=a.min?void 0:(a.text=a.cm.getLine(--a.line),a.ch=a.text.length,!0)}function k(a){for(;;){var b=a.text.indexOf(">",a.ch);if(-1==b){if(i(a))continue;return}{if(h(a,b+1)){var c=a.text.lastIndexOf("/",b),d=c>-1&&!/\S/.test(a.text.slice(c+1,b));return a.ch=b+1,d?"selfClose":"regular"}a.ch=b+1}}}function l(a){for(;;){var b=a.ch?a.text.lastIndexOf("<",a.ch-1):-1;if(-1==b){if(j(a))continue;return}if(h(a,b+1)){f.lastIndex=b,a.ch=b;var c=f.exec(a.text);if(c&&c.index==b)return c}else a.ch=b}}function m(a){for(;;){f.lastIndex=a.ch;var b=f.exec(a.text);if(!b){if(i(a))continue;return}{if(h(a,b.index+1))return a.ch=b.index+b[0].length,b;a.ch=b.index+1}}}function n(a){for(;;){var b=a.ch?a.text.lastIndexOf(">",a.ch-1):-1;if(-1==b){if(j(a))continue;return}{if(h(a,b+1)){var c=a.text.lastIndexOf("/",b),d=c>-1&&!/\S/.test(a.text.slice(c+1,b));return a.ch=b+1,d?"selfClose":"regular"}a.ch=b}}}function o(a,c){for(var d=[];;){var f,e=m(a),g=a.line,h=a.ch-(e?e[0].length:0);if(!e||!(f=k(a)))return;if("selfClose"!=f)if(e[1]){for(var i=d.length-1;i>=0;--i)if(d[i]==e[2]){d.length=i;break}if(0>i&&(!c||c==e[2]))return{tag:e[2],from:b(g,h),to:b(a.line,a.ch)}}else d.push(e[2])}}function p(a,c){for(var d=[];;){var e=n(a);if(!e)return;if("selfClose"!=e){var f=a.line,g=a.ch,h=l(a);if(!h)return;if(h[1])d.push(h[2]);else{for(var i=d.length-1;i>=0;--i)if(d[i]==h[2]){d.length=i;break}if(0>i&&(!c||c==h[2]))return{tag:h[2],from:b(a.line,a.ch),to:b(f,g)}}}else l(a)}}var b=a.Pos,d="A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD",e=d+"-:.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040",f=new RegExp("<(/?)(["+d+"]["+e+"]*)","g");a.registerHelper("fold","xml",function(a,c){for(var d=new g(a,c.line,0);;){var f,e=m(d);if(!e||d.line!=c.line||!(f=k(d)))return;if(!e[1]&&"selfClose"!=f){var c=b(d.line,d.ch),h=o(d,e[2]);return h&&{from:c,to:h.from}}}}),a.findMatchingTag=function(a,d,e){var f=new g(a,d.line,d.ch,e);if(-1!=f.text.indexOf(">")||-1!=f.text.indexOf("<")){var h=k(f),i=h&&b(f.line,f.ch),j=h&&l(f);if(h&&j&&!(c(f,d)>0)){var m={from:b(f.line,f.ch),to:i,tag:j[2]};return"selfClose"==h?{open:m,close:null,at:"open"}:j[1]?{open:p(f,j[2]),close:m,at:"close"}:(f=new g(a,i.line,i.ch,e),{open:m,close:o(f,j[2]),at:"open"})}}},a.findEnclosingTag=function(a,b,c){for(var d=new g(a,b.line,b.ch,c);;){var e=p(d);if(!e)break;var f=new g(a,b.line,b.ch,c),h=o(f,e.tag);if(h)return{open:e,close:h}}},a.scanForClosingTag=function(a,b,c,d){var e=new g(a,b.line,b.ch,d?{from:0,to:d}:null);return o(e,c)}});
\ No newline at end of file
diff --git a/htdocs/Libs/DataTables-1.10.3/media/css/jquery.dataTables.css b/htdocs/Libs/DataTables-1.10.3/media/css/jquery.dataTables.css
new file mode 100644
index 0000000..eec02ef
--- /dev/null
+++ b/htdocs/Libs/DataTables-1.10.3/media/css/jquery.dataTables.css
@@ -0,0 +1,455 @@
+/*
+ * Table styles
+ */
+table.dataTable {
+  width: 100%;
+  margin: 0 auto;
+  clear: both;
+  border-collapse: separate;
+  border-spacing: 0;
+  /*
+   * Header and footer styles
+   */
+  /*
+   * Body styles
+   */
+}
+table.dataTable thead th,
+table.dataTable tfoot th {
+  font-weight: bold;
+}
+table.dataTable thead th,
+table.dataTable thead td {
+  padding: 10px 18px;
+  border-bottom: 1px solid #111;
+}
+table.dataTable thead th:active,
+table.dataTable thead td:active {
+  outline: none;
+}
+table.dataTable tfoot th,
+table.dataTable tfoot td {
+  padding: 10px 18px 6px 18px;
+  border-top: 1px solid #111;
+}
+table.dataTable thead .sorting,
+table.dataTable thead .sorting_asc,
+table.dataTable thead .sorting_desc {
+  cursor: pointer;
+  *cursor: hand;
+}
+table.dataTable thead .sorting,
+table.dataTable thead .sorting_asc,
+table.dataTable thead .sorting_desc,
+table.dataTable thead .sorting_asc_disabled,
+table.dataTable thead .sorting_desc_disabled {
+  background-repeat: no-repeat;
+  background-position: center right;
+}
+table.dataTable thead .sorting {
+  background-image: url("../images/sort_both.png");
+}
+table.dataTable thead .sorting_asc {
+  background-image: url("../images/sort_asc.png");
+}
+table.dataTable thead .sorting_desc {
+  background-image: url("../images/sort_desc.png");
+}
+table.dataTable thead .sorting_asc_disabled {
+  background-image: url("../images/sort_asc_disabled.png");
+}
+table.dataTable thead .sorting_desc_disabled {
+  background-image: url("../images/sort_desc_disabled.png");
+}
+table.dataTable tbody tr {
+  background-color: #ffffff;
+}
+table.dataTable tbody tr.selected {
+  background-color: #B0BED9;
+}
+table.dataTable tbody th,
+table.dataTable tbody td {
+  padding: 8px 10px;
+}
+table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {
+  border-top: 1px solid #ddd;
+}
+table.dataTable.row-border tbody tr:first-child th,
+table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,
+table.dataTable.display tbody tr:first-child td {
+  border-top: none;
+}
+table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
+  border-top: 1px solid #ddd;
+  border-right: 1px solid #ddd;
+}
+table.dataTable.cell-border tbody tr th:first-child,
+table.dataTable.cell-border tbody tr td:first-child {
+  border-left: 1px solid #ddd;
+}
+table.dataTable.cell-border tbody tr:first-child th,
+table.dataTable.cell-border tbody tr:first-child td {
+  border-top: none;
+}
+table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
+  background-color: #f9f9f9;
+}
+table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {
+  background-color: #abb9d3;
+}
+table.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {
+  background-color: whitesmoke;
+}
+table.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {
+  background-color: #a9b7d1;
+}
+table.dataTable.order-column tbody tr > .sorting_1,
+table.dataTable.order-column tbody tr > .sorting_2,
+table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
+table.dataTable.display tbody tr > .sorting_2,
+table.dataTable.display tbody tr > .sorting_3 {
+  background-color: #f9f9f9;
+}
+table.dataTable.order-column tbody tr.selected > .sorting_1,
+table.dataTable.order-column tbody tr.selected > .sorting_2,
+table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,
+table.dataTable.display tbody tr.selected > .sorting_2,
+table.dataTable.display tbody tr.selected > .sorting_3 {
+  background-color: #acbad4;
+}
+table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {
+  background-color: #f1f1f1;
+}
+table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {
+  background-color: #f3f3f3;
+}
+table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {
+  background-color: whitesmoke;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {
+  background-color: #a6b3cd;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {
+  background-color: #a7b5ce;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {
+  background-color: #a9b6d0;
+}
+table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {
+  background-color: #f9f9f9;
+}
+table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {
+  background-color: #fbfbfb;
+}
+table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {
+  background-color: #fdfdfd;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {
+  background-color: #acbad4;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {
+  background-color: #adbbd6;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {
+  background-color: #afbdd8;
+}
+table.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {
+  background-color: #eaeaea;
+}
+table.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {
+  background-color: #ebebeb;
+}
+table.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {
+  background-color: #eeeeee;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {
+  background-color: #a1aec7;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {
+  background-color: #a2afc8;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {
+  background-color: #a4b2cb;
+}
+table.dataTable.no-footer {
+  border-bottom: 1px solid #111;
+}
+table.dataTable.nowrap th, table.dataTable.nowrap td {
+  white-space: nowrap;
+}
+table.dataTable.compact thead th,
+table.dataTable.compact thead td {
+  padding: 4px 17px 4px 4px;
+}
+table.dataTable.compact tfoot th,
+table.dataTable.compact tfoot td {
+  padding: 4px;
+}
+table.dataTable.compact tbody th,
+table.dataTable.compact tbody td {
+  padding: 4px;
+}
+table.dataTable th.dt-left,
+table.dataTable td.dt-left {
+  text-align: left;
+}
+table.dataTable th.dt-center,
+table.dataTable td.dt-center,
+table.dataTable td.dataTables_empty {
+  text-align: center;
+}
+table.dataTable th.dt-right,
+table.dataTable td.dt-right {
+  text-align: right;
+}
+table.dataTable th.dt-justify,
+table.dataTable td.dt-justify {
+  text-align: justify;
+}
+table.dataTable th.dt-nowrap,
+table.dataTable td.dt-nowrap {
+  white-space: nowrap;
+}
+table.dataTable thead th.dt-head-left,
+table.dataTable thead td.dt-head-left,
+table.dataTable tfoot th.dt-head-left,
+table.dataTable tfoot td.dt-head-left {
+  text-align: left;
+}
+table.dataTable thead th.dt-head-center,
+table.dataTable thead td.dt-head-center,
+table.dataTable tfoot th.dt-head-center,
+table.dataTable tfoot td.dt-head-center {
+  text-align: center;
+}
+table.dataTable thead th.dt-head-right,
+table.dataTable thead td.dt-head-right,
+table.dataTable tfoot th.dt-head-right,
+table.dataTable tfoot td.dt-head-right {
+  text-align: right;
+}
+table.dataTable thead th.dt-head-justify,
+table.dataTable thead td.dt-head-justify,
+table.dataTable tfoot th.dt-head-justify,
+table.dataTable tfoot td.dt-head-justify {
+  text-align: justify;
+}
+table.dataTable thead th.dt-head-nowrap,
+table.dataTable thead td.dt-head-nowrap,
+table.dataTable tfoot th.dt-head-nowrap,
+table.dataTable tfoot td.dt-head-nowrap {
+  white-space: nowrap;
+}
+table.dataTable tbody th.dt-body-left,
+table.dataTable tbody td.dt-body-left {
+  text-align: left;
+}
+table.dataTable tbody th.dt-body-center,
+table.dataTable tbody td.dt-body-center {
+  text-align: center;
+}
+table.dataTable tbody th.dt-body-right,
+table.dataTable tbody td.dt-body-right {
+  text-align: right;
+}
+table.dataTable tbody th.dt-body-justify,
+table.dataTable tbody td.dt-body-justify {
+  text-align: justify;
+}
+table.dataTable tbody th.dt-body-nowrap,
+table.dataTable tbody td.dt-body-nowrap {
+  white-space: nowrap;
+}
+
+table.dataTable,
+table.dataTable th,
+table.dataTable td {
+  -webkit-box-sizing: content-box;
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+
+/*
+ * Control feature layout
+ */
+.dataTables_wrapper {
+  position: relative;
+  clear: both;
+  *zoom: 1;
+  zoom: 1;
+}
+.dataTables_wrapper .dataTables_length {
+  float: left;
+}
+.dataTables_wrapper .dataTables_filter {
+  float: right;
+  text-align: right;
+}
+.dataTables_wrapper .dataTables_filter input {
+  margin-left: 0.5em;
+}
+.dataTables_wrapper .dataTables_info {
+  clear: both;
+  float: left;
+  padding-top: 0.755em;
+}
+.dataTables_wrapper .dataTables_paginate {
+  float: right;
+  text-align: right;
+  padding-top: 0.25em;
+}
+.dataTables_wrapper .dataTables_paginate .paginate_button {
+  box-sizing: border-box;
+  display: inline-block;
+  min-width: 1.5em;
+  padding: 0.5em 1em;
+  margin-left: 2px;
+  text-align: center;
+  text-decoration: none !important;
+  cursor: pointer;
+  *cursor: hand;
+  color: #333 !important;
+  border: 1px solid transparent;
+}
+.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
+  color: #333 !important;
+  border: 1px solid #cacaca;
+  background-color: white;
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));
+  /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);
+  /* Chrome10+,Safari5.1+ */
+  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);
+  /* FF3.6+ */
+  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);
+  /* IE10+ */
+  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);
+  /* Opera 11.10+ */
+  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);
+  /* W3C */
+}
+.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {
+  cursor: default;
+  color: #666 !important;
+  border: 1px solid transparent;
+  background: transparent;
+  box-shadow: none;
+}
+.dataTables_wrapper .dataTables_paginate .paginate_button:hover {
+  color: white !important;
+  border: 1px solid #111;
+  background-color: #585858;
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));
+  /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);
+  /* Chrome10+,Safari5.1+ */
+  background: -moz-linear-gradient(top, #585858 0%, #111 100%);
+  /* FF3.6+ */
+  background: -ms-linear-gradient(top, #585858 0%, #111 100%);
+  /* IE10+ */
+  background: -o-linear-gradient(top, #585858 0%, #111 100%);
+  /* Opera 11.10+ */
+  background: linear-gradient(to bottom, #585858 0%, #111 100%);
+  /* W3C */
+}
+.dataTables_wrapper .dataTables_paginate .paginate_button:active {
+  outline: none;
+  background-color: #2b2b2b;
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));
+  /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
+  /* Chrome10+,Safari5.1+ */
+  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
+  /* FF3.6+ */
+  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
+  /* IE10+ */
+  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
+  /* Opera 11.10+ */
+  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);
+  /* W3C */
+  box-shadow: inset 0 0 3px #111;
+}
+.dataTables_wrapper .dataTables_paginate .ellipsis {
+  padding: 0 1em;
+}
+.dataTables_wrapper .dataTables_processing {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  width: 100%;
+  height: 40px;
+  margin-left: -50%;
+  margin-top: -25px;
+  padding-top: 20px;
+  text-align: center;
+  font-size: 1.2em;
+  background-color: white;
+  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));
+  /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* Chrome10+,Safari5.1+ */
+  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* FF3.6+ */
+  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* IE10+ */
+  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* Opera 11.10+ */
+  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* W3C */
+}
+.dataTables_wrapper .dataTables_length,
+.dataTables_wrapper .dataTables_filter,
+.dataTables_wrapper .dataTables_info,
+.dataTables_wrapper .dataTables_processing,
+.dataTables_wrapper .dataTables_paginate {
+  color: #333;
+}
+.dataTables_wrapper .dataTables_scroll {
+  clear: both;
+}
+.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {
+  *margin-top: -1px;
+  -webkit-overflow-scrolling: touch;
+}
+.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,
+.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {
+  height: 0;
+  overflow: hidden;
+  margin: 0 !important;
+  padding: 0 !important;
+}
+.dataTables_wrapper.no-footer .dataTables_scrollBody {
+  border-bottom: 1px solid #111;
+}
+.dataTables_wrapper.no-footer div.dataTables_scrollHead table,
+.dataTables_wrapper.no-footer div.dataTables_scrollBody table {
+  border-bottom: none;
+}
+.dataTables_wrapper:after {
+  visibility: hidden;
+  display: block;
+  content: "";
+  clear: both;
+  height: 0;
+}
+
+@media screen and (max-width: 767px) {
+  .dataTables_wrapper .dataTables_info,
+  .dataTables_wrapper .dataTables_paginate {
+    float: none;
+    text-align: center;
+  }
+  .dataTables_wrapper .dataTables_paginate {
+    margin-top: 0.5em;
+  }
+}
+@media screen and (max-width: 640px) {
+  .dataTables_wrapper .dataTables_length,
+  .dataTables_wrapper .dataTables_filter {
+    float: none;
+    text-align: center;
+  }
+  .dataTables_wrapper .dataTables_filter {
+    margin-top: 0.5em;
+  }
+}
diff --git a/htdocs/Libs/DataTables-1.10.3/media/css/jquery.dataTables.min.css b/htdocs/Libs/DataTables-1.10.3/media/css/jquery.dataTables.min.css
new file mode 100644
index 0000000..2edb32f
--- /dev/null
+++ b/htdocs/Libs/DataTables-1.10.3/media/css/jquery.dataTables.min.css
@@ -0,0 +1 @@
+table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px;border-bottom:1px solid #111}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px;border-top:1px solid #111}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc{cursor:pointer;*cursor:hand}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url("../images/sort_both.png")}table.dataTable thead .sorting_asc{background-image:url("../images/sort_asc.png")}table.dataTable thead .sorting_desc{background-image:url("../images/sort_desc.png")}table.dataTable thead .sorting_asc_disabled{background-image:url("../images/sort_asc_disabled.png")}table.dataTable thead .sorting_desc_disabled{background-image:url("../images/sort_desc_disabled.png")}table.dataTable tbody tr{background-color:#fff}table.dataTable tbody tr.selected{background-color:#B0BED9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#abb9d3}table.dataTable.hover tbody tr:hover,table.dataTable.display tbody tr:hover{background-color:#f5f5f5}table.dataTable.hover tbody tr:hover.selected,table.dataTable.display tbody tr:hover.selected{background-color:#a9b7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#f9f9f9}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad4}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:#f5f5f5}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b3cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a7b5ce}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b6d0}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#f9f9f9}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fbfbfb}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fdfdfd}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad4}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#adbbd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{background-color:#ebebeb}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{background-color:#eee}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{background-color:#a1aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{background-color:#a2afc8}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{background-color:#a4b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px 4px 4px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable,table.dataTable th,table.dataTable td{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both;*zoom:1;zoom:1}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{margin-left:0.5em}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:0.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:0.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #cacaca;background-color:#fff;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(100%, #dcdcdc));background:-webkit-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-moz-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-ms-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-o-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:linear-gradient(to bottom, #fff 0%, #dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;background:-webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255,255,255,0)), color-stop(25%, rgba(255,255,255,0.9)), color-stop(75%, rgba(255,255,255,0.9)), color-stop(100%, rgba(255,255,255,0)));background:-webkit-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-o-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead table,.dataTables_wrapper.no-footer div.dataTables_scrollBody table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:0.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:0.5em}}
diff --git a/htdocs/Libs/DataTables-1.10.3/media/css/jquery.dataTables_themeroller.css b/htdocs/Libs/DataTables-1.10.3/media/css/jquery.dataTables_themeroller.css
new file mode 100644
index 0000000..1426a44
--- /dev/null
+++ b/htdocs/Libs/DataTables-1.10.3/media/css/jquery.dataTables_themeroller.css
@@ -0,0 +1,416 @@
+/*
+ * Table styles
+ */
+table.dataTable {
+  width: 100%;
+  margin: 0 auto;
+  clear: both;
+  border-collapse: separate;
+  border-spacing: 0;
+  /*
+   * Header and footer styles
+   */
+  /*
+   * Body styles
+   */
+}
+table.dataTable thead th,
+table.dataTable thead td,
+table.dataTable tfoot th,
+table.dataTable tfoot td {
+  padding: 4px 10px;
+}
+table.dataTable thead th,
+table.dataTable tfoot th {
+  font-weight: bold;
+}
+table.dataTable thead th:active,
+table.dataTable thead td:active {
+  outline: none;
+}
+table.dataTable thead .sorting_asc,
+table.dataTable thead .sorting_desc,
+table.dataTable thead .sorting {
+  cursor: pointer;
+  *cursor: hand;
+}
+table.dataTable thead th div.DataTables_sort_wrapper {
+  position: relative;
+  padding-right: 10px;
+}
+table.dataTable thead th div.DataTables_sort_wrapper span {
+  position: absolute;
+  top: 50%;
+  margin-top: -8px;
+  right: -5px;
+}
+table.dataTable thead th.ui-state-default {
+  border-right-width: 0;
+}
+table.dataTable thead th.ui-state-default:last-child {
+  border-right-width: 1px;
+}
+table.dataTable tbody tr {
+  background-color: #ffffff;
+}
+table.dataTable tbody tr.selected {
+  background-color: #B0BED9;
+}
+table.dataTable tbody th,
+table.dataTable tbody td {
+  padding: 8px 10px;
+}
+table.dataTable th.center,
+table.dataTable td.center,
+table.dataTable td.dataTables_empty {
+  text-align: center;
+}
+table.dataTable th.right,
+table.dataTable td.right {
+  text-align: right;
+}
+table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {
+  border-top: 1px solid #ddd;
+}
+table.dataTable.row-border tbody tr:first-child th,
+table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,
+table.dataTable.display tbody tr:first-child td {
+  border-top: none;
+}
+table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
+  border-top: 1px solid #ddd;
+  border-right: 1px solid #ddd;
+}
+table.dataTable.cell-border tbody tr th:first-child,
+table.dataTable.cell-border tbody tr td:first-child {
+  border-left: 1px solid #ddd;
+}
+table.dataTable.cell-border tbody tr:first-child th,
+table.dataTable.cell-border tbody tr:first-child td {
+  border-top: none;
+}
+table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
+  background-color: #f9f9f9;
+}
+table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {
+  background-color: #abb9d3;
+}
+table.dataTable.hover tbody tr:hover,
+table.dataTable.hover tbody tr.odd:hover,
+table.dataTable.hover tbody tr.even:hover, table.dataTable.display tbody tr:hover,
+table.dataTable.display tbody tr.odd:hover,
+table.dataTable.display tbody tr.even:hover {
+  background-color: whitesmoke;
+}
+table.dataTable.hover tbody tr:hover.selected,
+table.dataTable.hover tbody tr.odd:hover.selected,
+table.dataTable.hover tbody tr.even:hover.selected, table.dataTable.display tbody tr:hover.selected,
+table.dataTable.display tbody tr.odd:hover.selected,
+table.dataTable.display tbody tr.even:hover.selected {
+  background-color: #a9b7d1;
+}
+table.dataTable.order-column tbody tr > .sorting_1,
+table.dataTable.order-column tbody tr > .sorting_2,
+table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
+table.dataTable.display tbody tr > .sorting_2,
+table.dataTable.display tbody tr > .sorting_3 {
+  background-color: #f9f9f9;
+}
+table.dataTable.order-column tbody tr.selected > .sorting_1,
+table.dataTable.order-column tbody tr.selected > .sorting_2,
+table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,
+table.dataTable.display tbody tr.selected > .sorting_2,
+table.dataTable.display tbody tr.selected > .sorting_3 {
+  background-color: #acbad4;
+}
+table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {
+  background-color: #f1f1f1;
+}
+table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {
+  background-color: #f3f3f3;
+}
+table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {
+  background-color: whitesmoke;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {
+  background-color: #a6b3cd;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {
+  background-color: #a7b5ce;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {
+  background-color: #a9b6d0;
+}
+table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {
+  background-color: #f9f9f9;
+}
+table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {
+  background-color: #fbfbfb;
+}
+table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {
+  background-color: #fdfdfd;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {
+  background-color: #acbad4;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {
+  background-color: #adbbd6;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {
+  background-color: #afbdd8;
+}
+table.dataTable.display tbody tr:hover > .sorting_1,
+table.dataTable.display tbody tr.odd:hover > .sorting_1,
+table.dataTable.display tbody tr.even:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1,
+table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_1,
+table.dataTable.order-column.hover tbody tr.even:hover > .sorting_1 {
+  background-color: #eaeaea;
+}
+table.dataTable.display tbody tr:hover > .sorting_2,
+table.dataTable.display tbody tr.odd:hover > .sorting_2,
+table.dataTable.display tbody tr.even:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2,
+table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_2,
+table.dataTable.order-column.hover tbody tr.even:hover > .sorting_2 {
+  background-color: #ebebeb;
+}
+table.dataTable.display tbody tr:hover > .sorting_3,
+table.dataTable.display tbody tr.odd:hover > .sorting_3,
+table.dataTable.display tbody tr.even:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3,
+table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_3,
+table.dataTable.order-column.hover tbody tr.even:hover > .sorting_3 {
+  background-color: #eeeeee;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_1,
+table.dataTable.display tbody tr.odd:hover.selected > .sorting_1,
+table.dataTable.display tbody tr.even:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1,
+table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_1,
+table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_1 {
+  background-color: #a1aec7;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_2,
+table.dataTable.display tbody tr.odd:hover.selected > .sorting_2,
+table.dataTable.display tbody tr.even:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2,
+table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_2,
+table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_2 {
+  background-color: #a2afc8;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_3,
+table.dataTable.display tbody tr.odd:hover.selected > .sorting_3,
+table.dataTable.display tbody tr.even:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3,
+table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_3,
+table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_3 {
+  background-color: #a4b2cb;
+}
+table.dataTable.nowrap th, table.dataTable.nowrap td {
+  white-space: nowrap;
+}
+table.dataTable.compact thead th,
+table.dataTable.compact thead td {
+  padding: 5px 9px;
+}
+table.dataTable.compact tfoot th,
+table.dataTable.compact tfoot td {
+  padding: 5px 9px 3px 9px;
+}
+table.dataTable.compact tbody th,
+table.dataTable.compact tbody td {
+  padding: 4px 5px;
+}
+table.dataTable th.dt-left,
+table.dataTable td.dt-left {
+  text-align: left;
+}
+table.dataTable th.dt-center,
+table.dataTable td.dt-center,
+table.dataTable td.dataTables_empty {
+  text-align: center;
+}
+table.dataTable th.dt-right,
+table.dataTable td.dt-right {
+  text-align: right;
+}
+table.dataTable th.dt-justify,
+table.dataTable td.dt-justify {
+  text-align: justify;
+}
+table.dataTable th.dt-nowrap,
+table.dataTable td.dt-nowrap {
+  white-space: nowrap;
+}
+table.dataTable thead th.dt-head-left,
+table.dataTable thead td.dt-head-left,
+table.dataTable tfoot th.dt-head-left,
+table.dataTable tfoot td.dt-head-left {
+  text-align: left;
+}
+table.dataTable thead th.dt-head-center,
+table.dataTable thead td.dt-head-center,
+table.dataTable tfoot th.dt-head-center,
+table.dataTable tfoot td.dt-head-center {
+  text-align: center;
+}
+table.dataTable thead th.dt-head-right,
+table.dataTable thead td.dt-head-right,
+table.dataTable tfoot th.dt-head-right,
+table.dataTable tfoot td.dt-head-right {
+  text-align: right;
+}
+table.dataTable thead th.dt-head-justify,
+table.dataTable thead td.dt-head-justify,
+table.dataTable tfoot th.dt-head-justify,
+table.dataTable tfoot td.dt-head-justify {
+  text-align: justify;
+}
+table.dataTable thead th.dt-head-nowrap,
+table.dataTable thead td.dt-head-nowrap,
+table.dataTable tfoot th.dt-head-nowrap,
+table.dataTable tfoot td.dt-head-nowrap {
+  white-space: nowrap;
+}
+table.dataTable tbody th.dt-body-left,
+table.dataTable tbody td.dt-body-left {
+  text-align: left;
+}
+table.dataTable tbody th.dt-body-center,
+table.dataTable tbody td.dt-body-center {
+  text-align: center;
+}
+table.dataTable tbody th.dt-body-right,
+table.dataTable tbody td.dt-body-right {
+  text-align: right;
+}
+table.dataTable tbody th.dt-body-justify,
+table.dataTable tbody td.dt-body-justify {
+  text-align: justify;
+}
+table.dataTable tbody th.dt-body-nowrap,
+table.dataTable tbody td.dt-body-nowrap {
+  white-space: nowrap;
+}
+
+table.dataTable,
+table.dataTable th,
+table.dataTable td {
+  -webkit-box-sizing: content-box;
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+
+/*
+ * Control feature layout
+ */
+.dataTables_wrapper {
+  position: relative;
+  clear: both;
+  *zoom: 1;
+  zoom: 1;
+}
+.dataTables_wrapper .dataTables_length {
+  float: left;
+}
+.dataTables_wrapper .dataTables_filter {
+  float: right;
+  text-align: right;
+}
+.dataTables_wrapper .dataTables_filter input {
+  margin-left: 0.5em;
+}
+.dataTables_wrapper .dataTables_info {
+  clear: both;
+  float: left;
+  padding-top: 0.55em;
+}
+.dataTables_wrapper .dataTables_paginate {
+  float: right;
+  text-align: right;
+}
+.dataTables_wrapper .dataTables_paginate .fg-button {
+  box-sizing: border-box;
+  display: inline-block;
+  min-width: 1.5em;
+  padding: 0.5em;
+  margin-left: 2px;
+  text-align: center;
+  text-decoration: none !important;
+  cursor: pointer;
+  *cursor: hand;
+  color: #333 !important;
+  border: 1px solid transparent;
+}
+.dataTables_wrapper .dataTables_paginate .fg-button:active {
+  outline: none;
+}
+.dataTables_wrapper .dataTables_paginate .fg-button:first-child {
+  border-top-left-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.dataTables_wrapper .dataTables_paginate .fg-button:last-child {
+  border-top-right-radius: 3px;
+  border-bottom-right-radius: 3px;
+}
+.dataTables_wrapper .dataTables_processing {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  width: 100%;
+  height: 40px;
+  margin-left: -50%;
+  margin-top: -25px;
+  padding-top: 20px;
+  text-align: center;
+  font-size: 1.2em;
+  background-color: white;
+  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));
+  /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* Chrome10+,Safari5.1+ */
+  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* FF3.6+ */
+  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* IE10+ */
+  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* Opera 11.10+ */
+  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* W3C */
+}
+.dataTables_wrapper .dataTables_length,
+.dataTables_wrapper .dataTables_filter,
+.dataTables_wrapper .dataTables_info,
+.dataTables_wrapper .dataTables_processing,
+.dataTables_wrapper .dataTables_paginate {
+  color: #333;
+}
+.dataTables_wrapper .dataTables_scroll {
+  clear: both;
+}
+.dataTables_wrapper .dataTables_scrollBody {
+  *margin-top: -1px;
+  -webkit-overflow-scrolling: touch;
+}
+.dataTables_wrapper .ui-widget-header {
+  font-weight: normal;
+}
+.dataTables_wrapper .ui-toolbar {
+  padding: 8px;
+}
+.dataTables_wrapper:after {
+  visibility: hidden;
+  display: block;
+  content: "";
+  clear: both;
+  height: 0;
+}
+
+@media screen and (max-width: 767px) {
+  .dataTables_wrapper .dataTables_length,
+  .dataTables_wrapper .dataTables_filter,
+  .dataTables_wrapper .dataTables_info,
+  .dataTables_wrapper .dataTables_paginate {
+    float: none;
+    text-align: center;
+  }
+  .dataTables_wrapper .dataTables_filter,
+  .dataTables_wrapper .dataTables_paginate {
+    margin-top: 0.5em;
+  }
+}
diff --git a/htdocs/Libs/DataTables-1.10.3/media/images/favicon.ico b/htdocs/Libs/DataTables-1.10.3/media/images/favicon.ico
new file mode 100644
index 0000000..6eeaa2a
--- /dev/null
+++ b/htdocs/Libs/DataTables-1.10.3/media/images/favicon.ico
Binary files differ
diff --git a/htdocs/Libs/DataTables-1.10.3/media/images/sort_asc.png b/htdocs/Libs/DataTables-1.10.3/media/images/sort_asc.png
new file mode 100644
index 0000000..e1ba61a
--- /dev/null
+++ b/htdocs/Libs/DataTables-1.10.3/media/images/sort_asc.png
Binary files differ
diff --git a/htdocs/Libs/DataTables-1.10.3/media/images/sort_asc_disabled.png b/htdocs/Libs/DataTables-1.10.3/media/images/sort_asc_disabled.png
new file mode 100644
index 0000000..fb11dfe
--- /dev/null
+++ b/htdocs/Libs/DataTables-1.10.3/media/images/sort_asc_disabled.png
Binary files differ
diff --git a/htdocs/Libs/DataTables-1.10.3/media/images/sort_both.png b/htdocs/Libs/DataTables-1.10.3/media/images/sort_both.png
new file mode 100644
index 0000000..af5bc7c
--- /dev/null
+++ b/htdocs/Libs/DataTables-1.10.3/media/images/sort_both.png
Binary files differ
diff --git a/htdocs/Libs/DataTables-1.10.3/media/images/sort_desc.png b/htdocs/Libs/DataTables-1.10.3/media/images/sort_desc.png
new file mode 100644
index 0000000..0e156de
--- /dev/null
+++ b/htdocs/Libs/DataTables-1.10.3/media/images/sort_desc.png
Binary files differ
diff --git a/htdocs/Libs/DataTables-1.10.3/media/images/sort_desc_disabled.png b/htdocs/Libs/DataTables-1.10.3/media/images/sort_desc_disabled.png
new file mode 100644
index 0000000..c9fdd8a
--- /dev/null
+++ b/htdocs/Libs/DataTables-1.10.3/media/images/sort_desc_disabled.png
Binary files differ
diff --git a/htdocs/Libs/DataTables-1.10.3/media/js/jquery.dataTables.js b/htdocs/Libs/DataTables-1.10.3/media/js/jquery.dataTables.js
new file mode 100644
index 0000000..2a9bdb3
--- /dev/null
+++ b/htdocs/Libs/DataTables-1.10.3/media/js/jquery.dataTables.js
@@ -0,0 +1,14951 @@
+/*! DataTables 1.10.7
+ * ©2008-2014 SpryMedia Ltd - datatables.net/license
+ */
+
+/**
+ * @summary     DataTables
+ * @description Paginate, search and order HTML tables
+ * @version     1.10.7
+ * @file        jquery.dataTables.js
+ * @author      SpryMedia Ltd (www.sprymedia.co.uk)
+ * @contact     www.sprymedia.co.uk/contact
+ * @copyright   Copyright 2008-2014 SpryMedia Ltd.
+ *
+ * This source file is free software, available under the following license:
+ *   MIT license - http://datatables.net/license
+ *
+ * This source file 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 license files for details.
+ *
+ * For details please refer to: http://www.datatables.net
+ */
+
+/*jslint evil: true, undef: true, browser: true */
+/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
+
+(/** @lends <global> */function( window, document, undefined ) {
+
+(function( factory ) {
+	"use strict";
+
+	if ( typeof define === 'function' && define.amd ) {
+		// Define as an AMD module if possible
+		define( 'datatables', ['jquery'], factory );
+	}
+    else if ( typeof exports === 'object' ) {
+        // Node/CommonJS
+        module.exports = factory( require( 'jquery' ) );
+    }
+	else if ( jQuery && !jQuery.fn.dataTable ) {
+		// Define using browser globals otherwise
+		// Prevent multiple instantiations if the script is loaded twice
+		factory( jQuery );
+	}
+}
+(/** @lends <global> */function( $ ) {
+	"use strict";
+
+	/**
+	 * DataTables is a plug-in for the jQuery Javascript library. It is a highly
+	 * flexible tool, based upon the foundations of progressive enhancement,
+	 * which will add advanced interaction controls to any HTML table. For a
+	 * full list of features please refer to
+	 * [DataTables.net](href="http://datatables.net).
+	 *
+	 * Note that the `DataTable` object is not a global variable but is aliased
+	 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
+	 * be  accessed.
+	 *
+	 *  @class
+	 *  @param {object} [init={}] Configuration object for DataTables. Options
+	 *    are defined by {@link DataTable.defaults}
+	 *  @requires jQuery 1.7+
+	 *
+	 *  @example
+	 *    // Basic initialisation
+	 *    $(document).ready( function {
+	 *      $('#example').dataTable();
+	 *    } );
+	 *
+	 *  @example
+	 *    // Initialisation with configuration options - in this case, disable
+	 *    // pagination and sorting.
+	 *    $(document).ready( function {
+	 *      $('#example').dataTable( {
+	 *        "paginate": false,
+	 *        "sort": false
+	 *      } );
+	 *    } );
+	 */
+	var DataTable;
+
+	
+	/*
+	 * It is useful to have variables which are scoped locally so only the
+	 * DataTables functions can access them and they don't leak into global space.
+	 * At the same time these functions are often useful over multiple files in the
+	 * core and API, so we list, or at least document, all variables which are used
+	 * by DataTables as private variables here. This also ensures that there is no
+	 * clashing of variable names and that they can easily referenced for reuse.
+	 */
+	
+	
+	// Defined else where
+	//  _selector_run
+	//  _selector_opts
+	//  _selector_first
+	//  _selector_row_indexes
+	
+	var _ext; // DataTable.ext
+	var _Api; // DataTable.Api
+	var _api_register; // DataTable.Api.register
+	var _api_registerPlural; // DataTable.Api.registerPlural
+	
+	var _re_dic = {};
+	var _re_new_lines = /[\r\n]/g;
+	var _re_html = /<.*?>/g;
+	var _re_date_start = /^[\w\+\-]/;
+	var _re_date_end = /[\w\+\-]$/;
+	
+	// Escape regular expression special characters
+	var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
+	
+	// http://en.wikipedia.org/wiki/Foreign_exchange_market
+	// - \u20BD - Russian ruble.
+	// - \u20a9 - South Korean Won
+	// - \u20BA - Turkish Lira
+	// - \u20B9 - Indian Rupee
+	// - R - Brazil (R$) and South Africa
+	// - fr - Swiss Franc
+	// - kr - Swedish krona, Norwegian krone and Danish krone
+	// - \u2009 is thin space and \u202F is narrow no-break space, both used in many
+	//   standards as thousands separators.
+	var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
+	
+	
+	var _empty = function ( d ) {
+		return !d || d === true || d === '-' ? true : false;
+	};
+	
+	
+	var _intVal = function ( s ) {
+		var integer = parseInt( s, 10 );
+		return !isNaN(integer) && isFinite(s) ? integer : null;
+	};
+	
+	// Convert from a formatted number with characters other than `.` as the
+	// decimal place, to a Javascript number
+	var _numToDecimal = function ( num, decimalPoint ) {
+		// Cache created regular expressions for speed as this function is called often
+		if ( ! _re_dic[ decimalPoint ] ) {
+			_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
+		}
+		return typeof num === 'string' && decimalPoint !== '.' ?
+			num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
+			num;
+	};
+	
+	
+	var _isNumber = function ( d, decimalPoint, formatted ) {
+		var strType = typeof d === 'string';
+	
+		// If empty return immediately so there must be a number if it is a
+		// formatted string (this stops the string "k", or "kr", etc being detected
+		// as a formatted number for currency
+		if ( _empty( d ) ) {
+			return true;
+		}
+	
+		if ( decimalPoint && strType ) {
+			d = _numToDecimal( d, decimalPoint );
+		}
+	
+		if ( formatted && strType ) {
+			d = d.replace( _re_formatted_numeric, '' );
+		}
+	
+		return !isNaN( parseFloat(d) ) && isFinite( d );
+	};
+	
+	
+	// A string without HTML in it can be considered to be HTML still
+	var _isHtml = function ( d ) {
+		return _empty( d ) || typeof d === 'string';
+	};
+	
+	
+	var _htmlNumeric = function ( d, decimalPoint, formatted ) {
+		if ( _empty( d ) ) {
+			return true;
+		}
+	
+		var html = _isHtml( d );
+		return ! html ?
+			null :
+			_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
+				true :
+				null;
+	};
+	
+	
+	var _pluck = function ( a, prop, prop2 ) {
+		var out = [];
+		var i=0, ien=a.length;
+	
+		// Could have the test in the loop for slightly smaller code, but speed
+		// is essential here
+		if ( prop2 !== undefined ) {
+			for ( ; i<ien ; i++ ) {
+				if ( a[i] && a[i][ prop ] ) {
+					out.push( a[i][ prop ][ prop2 ] );
+				}
+			}
+		}
+		else {
+			for ( ; i<ien ; i++ ) {
+				if ( a[i] ) {
+					out.push( a[i][ prop ] );
+				}
+			}
+		}
+	
+		return out;
+	};
+	
+	
+	// Basically the same as _pluck, but rather than looping over `a` we use `order`
+	// as the indexes to pick from `a`
+	var _pluck_order = function ( a, order, prop, prop2 )
+	{
+		var out = [];
+		var i=0, ien=order.length;
+	
+		// Could have the test in the loop for slightly smaller code, but speed
+		// is essential here
+		if ( prop2 !== undefined ) {
+			for ( ; i<ien ; i++ ) {
+				if ( a[ order[i] ][ prop ] ) {
+					out.push( a[ order[i] ][ prop ][ prop2 ] );
+				}
+			}
+		}
+		else {
+			for ( ; i<ien ; i++ ) {
+				out.push( a[ order[i] ][ prop ] );
+			}
+		}
+	
+		return out;
+	};
+	
+	
+	var _range = function ( len, start )
+	{
+		var out = [];
+		var end;
+	
+		if ( start === undefined ) {
+			start = 0;
+			end = len;
+		}
+		else {
+			end = start;
+			start = len;
+		}
+	
+		for ( var i=start ; i<end ; i++ ) {
+			out.push( i );
+		}
+	
+		return out;
+	};
+	
+	
+	var _removeEmpty = function ( a )
+	{
+		var out = [];
+	
+		for ( var i=0, ien=a.length ; i<ien ; i++ ) {
+			if ( a[i] ) { // careful - will remove all falsy values!
+				out.push( a[i] );
+			}
+		}
+	
+		return out;
+	};
+	
+	
+	var _stripHtml = function ( d ) {
+		return d.replace( _re_html, '' );
+	};
+	
+	
+	/**
+	 * Find the unique elements in a source array.
+	 *
+	 * @param  {array} src Source array
+	 * @return {array} Array of unique items
+	 * @ignore
+	 */
+	var _unique = function ( src )
+	{
+		// A faster unique method is to use object keys to identify used values,
+		// but this doesn't work with arrays or objects, which we must also
+		// consider. See jsperf.com/compare-array-unique-versions/4 for more
+		// information.
+		var
+			out = [],
+			val,
+			i, ien=src.length,
+			j, k=0;
+	
+		again: for ( i=0 ; i<ien ; i++ ) {
+			val = src[i];
+	
+			for ( j=0 ; j<k ; j++ ) {
+				if ( out[j] === val ) {
+					continue again;
+				}
+			}
+	
+			out.push( val );
+			k++;
+		}
+	
+		return out;
+	};
+	
+	
+	
+	/**
+	 * Create a mapping object that allows camel case parameters to be looked up
+	 * for their Hungarian counterparts. The mapping is stored in a private
+	 * parameter called `_hungarianMap` which can be accessed on the source object.
+	 *  @param {object} o
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnHungarianMap ( o )
+	{
+		var
+			hungarian = 'a aa ai ao as b fn i m o s ',
+			match,
+			newKey,
+			map = {};
+	
+		$.each( o, function (key, val) {
+			match = key.match(/^([^A-Z]+?)([A-Z])/);
+	
+			if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
+			{
+				newKey = key.replace( match[0], match[2].toLowerCase() );
+				map[ newKey ] = key;
+	
+				if ( match[1] === 'o' )
+				{
+					_fnHungarianMap( o[key] );
+				}
+			}
+		} );
+	
+		o._hungarianMap = map;
+	}
+	
+	
+	/**
+	 * Convert from camel case parameters to Hungarian, based on a Hungarian map
+	 * created by _fnHungarianMap.
+	 *  @param {object} src The model object which holds all parameters that can be
+	 *    mapped.
+	 *  @param {object} user The object to convert from camel case to Hungarian.
+	 *  @param {boolean} force When set to `true`, properties which already have a
+	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
+	 *    won't be.
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnCamelToHungarian ( src, user, force )
+	{
+		if ( ! src._hungarianMap ) {
+			_fnHungarianMap( src );
+		}
+	
+		var hungarianKey;
+	
+		$.each( user, function (key, val) {
+			hungarianKey = src._hungarianMap[ key ];
+	
+			if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
+			{
+				// For objects, we need to buzz down into the object to copy parameters
+				if ( hungarianKey.charAt(0) === 'o' )
+				{
+					// Copy the camelCase options over to the hungarian
+					if ( ! user[ hungarianKey ] ) {
+						user[ hungarianKey ] = {};
+					}
+					$.extend( true, user[hungarianKey], user[key] );
+	
+					_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
+				}
+				else {
+					user[hungarianKey] = user[ key ];
+				}
+			}
+		} );
+	}
+	
+	
+	/**
+	 * Language compatibility - when certain options are given, and others aren't, we
+	 * need to duplicate the values over, in order to provide backwards compatibility
+	 * with older language files.
+	 *  @param {object} oSettings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnLanguageCompat( lang )
+	{
+		var defaults = DataTable.defaults.oLanguage;
+		var zeroRecords = lang.sZeroRecords;
+	
+		/* Backwards compatibility - if there is no sEmptyTable given, then use the same as
+		 * sZeroRecords - assuming that is given.
+		 */
+		if ( ! lang.sEmptyTable && zeroRecords &&
+			defaults.sEmptyTable === "No data available in table" )
+		{
+			_fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
+		}
+	
+		/* Likewise with loading records */
+		if ( ! lang.sLoadingRecords && zeroRecords &&
+			defaults.sLoadingRecords === "Loading..." )
+		{
+			_fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
+		}
+	
+		// Old parameter name of the thousands separator mapped onto the new
+		if ( lang.sInfoThousands ) {
+			lang.sThousands = lang.sInfoThousands;
+		}
+	
+		var decimal = lang.sDecimal;
+		if ( decimal ) {
+			_addNumericSort( decimal );
+		}
+	}
+	
+	
+	/**
+	 * Map one parameter onto another
+	 *  @param {object} o Object to map
+	 *  @param {*} knew The new parameter name
+	 *  @param {*} old The old parameter name
+	 */
+	var _fnCompatMap = function ( o, knew, old ) {
+		if ( o[ knew ] !== undefined ) {
+			o[ old ] = o[ knew ];
+		}
+	};
+	
+	
+	/**
+	 * Provide backwards compatibility for the main DT options. Note that the new
+	 * options are mapped onto the old parameters, so this is an external interface
+	 * change only.
+	 *  @param {object} init Object to map
+	 */
+	function _fnCompatOpts ( init )
+	{
+		_fnCompatMap( init, 'ordering',      'bSort' );
+		_fnCompatMap( init, 'orderMulti',    'bSortMulti' );
+		_fnCompatMap( init, 'orderClasses',  'bSortClasses' );
+		_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
+		_fnCompatMap( init, 'order',         'aaSorting' );
+		_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );
+		_fnCompatMap( init, 'paging',        'bPaginate' );
+		_fnCompatMap( init, 'pagingType',    'sPaginationType' );
+		_fnCompatMap( init, 'pageLength',    'iDisplayLength' );
+		_fnCompatMap( init, 'searching',     'bFilter' );
+	
+		// Column search objects are in an array, so it needs to be converted
+		// element by element
+		var searchCols = init.aoSearchCols;
+	
+		if ( searchCols ) {
+			for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
+				if ( searchCols[i] ) {
+					_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
+				}
+			}
+		}
+	}
+	
+	
+	/**
+	 * Provide backwards compatibility for column options. Note that the new options
+	 * are mapped onto the old parameters, so this is an external interface change
+	 * only.
+	 *  @param {object} init Object to map
+	 */
+	function _fnCompatCols ( init )
+	{
+		_fnCompatMap( init, 'orderable',     'bSortable' );
+		_fnCompatMap( init, 'orderData',     'aDataSort' );
+		_fnCompatMap( init, 'orderSequence', 'asSorting' );
+		_fnCompatMap( init, 'orderDataType', 'sortDataType' );
+	
+		// orderData can be given as an integer
+		var dataSort = init.aDataSort;
+		if ( dataSort && ! $.isArray( dataSort ) ) {
+			init.aDataSort = [ dataSort ];
+		}
+	}
+	
+	
+	/**
+	 * Browser feature detection for capabilities, quirks
+	 *  @param {object} settings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnBrowserDetect( settings )
+	{
+		var browser = settings.oBrowser;
+	
+		// Scrolling feature / quirks detection
+		var n = $('<div/>')
+			.css( {
+				position: 'absolute',
+				top: 0,
+				left: 0,
+				height: 1,
+				width: 1,
+				overflow: 'hidden'
+			} )
+			.append(
+				$('<div/>')
+					.css( {
+						position: 'absolute',
+						top: 1,
+						left: 1,
+						width: 100,
+						overflow: 'scroll'
+					} )
+					.append(
+						$('<div class="test"/>')
+							.css( {
+								width: '100%',
+								height: 10
+							} )
+					)
+			)
+			.appendTo( 'body' );
+	
+		var test = n.find('.test');
+	
+		// IE6/7 will oversize a width 100% element inside a scrolling element, to
+		// include the width of the scrollbar, while other browsers ensure the inner
+		// element is contained without forcing scrolling
+		browser.bScrollOversize = test[0].offsetWidth === 100;
+	
+		// In rtl text layout, some browsers (most, but not all) will place the
+		// scrollbar on the left, rather than the right.
+		browser.bScrollbarLeft = Math.round( test.offset().left ) !== 1;
+	
+		n.remove();
+	}
+	
+	
+	/**
+	 * Array.prototype reduce[Right] method, used for browsers which don't support
+	 * JS 1.6. Done this way to reduce code size, since we iterate either way
+	 *  @param {object} settings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnReduce ( that, fn, init, start, end, inc )
+	{
+		var
+			i = start,
+			value,
+			isSet = false;
+	
+		if ( init !== undefined ) {
+			value = init;
+			isSet = true;
+		}
+	
+		while ( i !== end ) {
+			if ( ! that.hasOwnProperty(i) ) {
+				continue;
+			}
+	
+			value = isSet ?
+				fn( value, that[i], i, that ) :
+				that[i];
+	
+			isSet = true;
+			i += inc;
+		}
+	
+		return value;
+	}
+	
+	/**
+	 * Add a column to the list used for the table with default values
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {node} nTh The th element for this column
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnAddColumn( oSettings, nTh )
+	{
+		// Add column to aoColumns array
+		var oDefaults = DataTable.defaults.column;
+		var iCol = oSettings.aoColumns.length;
+		var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
+			"nTh": nTh ? nTh : document.createElement('th'),
+			"sTitle":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',
+			"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
+			"mData": oDefaults.mData ? oDefaults.mData : iCol,
+			idx: iCol
+		} );
+		oSettings.aoColumns.push( oCol );
+	
+		// Add search object for column specific search. Note that the `searchCols[ iCol ]`
+		// passed into extend can be undefined. This allows the user to give a default
+		// with only some of the parameters defined, and also not give a default
+		var searchCols = oSettings.aoPreSearchCols;
+		searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
+	
+		// Use the default column options function to initialise classes etc
+		_fnColumnOptions( oSettings, iCol, $(nTh).data() );
+	}
+	
+	
+	/**
+	 * Apply options for a column
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {int} iCol column index to consider
+	 *  @param {object} oOptions object with sType, bVisible and bSearchable etc
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnColumnOptions( oSettings, iCol, oOptions )
+	{
+		var oCol = oSettings.aoColumns[ iCol ];
+		var oClasses = oSettings.oClasses;
+		var th = $(oCol.nTh);
+	
+		// Try to get width information from the DOM. We can't get it from CSS
+		// as we'd need to parse the CSS stylesheet. `width` option can override
+		if ( ! oCol.sWidthOrig ) {
+			// Width attribute
+			oCol.sWidthOrig = th.attr('width') || null;
+	
+			// Style attribute
+			var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
+			if ( t ) {
+				oCol.sWidthOrig = t[1];
+			}
+		}
+	
+		/* User specified column options */
+		if ( oOptions !== undefined && oOptions !== null )
+		{
+			// Backwards compatibility
+			_fnCompatCols( oOptions );
+	
+			// Map camel case parameters to their Hungarian counterparts
+			_fnCamelToHungarian( DataTable.defaults.column, oOptions );
+	
+			/* Backwards compatibility for mDataProp */
+			if ( oOptions.mDataProp !== undefined && !oOptions.mData )
+			{
+				oOptions.mData = oOptions.mDataProp;
+			}
+	
+			if ( oOptions.sType )
+			{
+				oCol._sManualType = oOptions.sType;
+			}
+	
+			// `class` is a reserved word in Javascript, so we need to provide
+			// the ability to use a valid name for the camel case input
+			if ( oOptions.className && ! oOptions.sClass )
+			{
+				oOptions.sClass = oOptions.className;
+			}
+	
+			$.extend( oCol, oOptions );
+			_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
+	
+			/* iDataSort to be applied (backwards compatibility), but aDataSort will take
+			 * priority if defined
+			 */
+			if ( oOptions.iDataSort !== undefined )
+			{
+				oCol.aDataSort = [ oOptions.iDataSort ];
+			}
+			_fnMap( oCol, oOptions, "aDataSort" );
+		}
+	
+		/* Cache the data get and set functions for speed */
+		var mDataSrc = oCol.mData;
+		var mData = _fnGetObjectDataFn( mDataSrc );
+		var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
+	
+		var attrTest = function( src ) {
+			return typeof src === 'string' && src.indexOf('@') !== -1;
+		};
+		oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
+			attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
+		);
+	
+		oCol.fnGetData = function (rowData, type, meta) {
+			var innerData = mData( rowData, type, undefined, meta );
+	
+			return mRender && type ?
+				mRender( innerData, type, rowData, meta ) :
+				innerData;
+		};
+		oCol.fnSetData = function ( rowData, val, meta ) {
+			return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
+		};
+	
+		// Indicate if DataTables should read DOM data as an object or array
+		// Used in _fnGetRowElements
+		if ( typeof mDataSrc !== 'number' ) {
+			oSettings._rowReadObject = true;
+		}
+	
+		/* Feature sorting overrides column specific when off */
+		if ( !oSettings.oFeatures.bSort )
+		{
+			oCol.bSortable = false;
+			th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
+		}
+	
+		/* Check that the class assignment is correct for sorting */
+		var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
+		var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
+		if ( !oCol.bSortable || (!bAsc && !bDesc) )
+		{
+			oCol.sSortingClass = oClasses.sSortableNone;
+			oCol.sSortingClassJUI = "";
+		}
+		else if ( bAsc && !bDesc )
+		{
+			oCol.sSortingClass = oClasses.sSortableAsc;
+			oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
+		}
+		else if ( !bAsc && bDesc )
+		{
+			oCol.sSortingClass = oClasses.sSortableDesc;
+			oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
+		}
+		else
+		{
+			oCol.sSortingClass = oClasses.sSortable;
+			oCol.sSortingClassJUI = oClasses.sSortJUI;
+		}
+	}
+	
+	
+	/**
+	 * Adjust the table column widths for new data. Note: you would probably want to
+	 * do a redraw after calling this function!
+	 *  @param {object} settings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnAdjustColumnSizing ( settings )
+	{
+		/* Not interested in doing column width calculation if auto-width is disabled */
+		if ( settings.oFeatures.bAutoWidth !== false )
+		{
+			var columns = settings.aoColumns;
+	
+			_fnCalculateColumnWidths( settings );
+			for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
+			{
+				columns[i].nTh.style.width = columns[i].sWidth;
+			}
+		}
+	
+		var scroll = settings.oScroll;
+		if ( scroll.sY !== '' || scroll.sX !== '')
+		{
+			_fnScrollDraw( settings );
+		}
+	
+		_fnCallbackFire( settings, null, 'column-sizing', [settings] );
+	}
+	
+	
+	/**
+	 * Covert the index of a visible column to the index in the data array (take account
+	 * of hidden columns)
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {int} iMatch Visible column index to lookup
+	 *  @returns {int} i the data index
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnVisibleToColumnIndex( oSettings, iMatch )
+	{
+		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
+	
+		return typeof aiVis[iMatch] === 'number' ?
+			aiVis[iMatch] :
+			null;
+	}
+	
+	
+	/**
+	 * Covert the index of an index in the data array and convert it to the visible
+	 *   column index (take account of hidden columns)
+	 *  @param {int} iMatch Column index to lookup
+	 *  @param {object} oSettings dataTables settings object
+	 *  @returns {int} i the data index
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnColumnIndexToVisible( oSettings, iMatch )
+	{
+		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
+		var iPos = $.inArray( iMatch, aiVis );
+	
+		return iPos !== -1 ? iPos : null;
+	}
+	
+	
+	/**
+	 * Get the number of visible columns
+	 *  @param {object} oSettings dataTables settings object
+	 *  @returns {int} i the number of visible columns
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnVisbleColumns( oSettings )
+	{
+		return _fnGetColumns( oSettings, 'bVisible' ).length;
+	}
+	
+	
+	/**
+	 * Get an array of column indexes that match a given property
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {string} sParam Parameter in aoColumns to look for - typically
+	 *    bVisible or bSearchable
+	 *  @returns {array} Array of indexes with matched properties
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnGetColumns( oSettings, sParam )
+	{
+		var a = [];
+	
+		$.map( oSettings.aoColumns, function(val, i) {
+			if ( val[sParam] ) {
+				a.push( i );
+			}
+		} );
+	
+		return a;
+	}
+	
+	
+	/**
+	 * Calculate the 'type' of a column
+	 *  @param {object} settings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnColumnTypes ( settings )
+	{
+		var columns = settings.aoColumns;
+		var data = settings.aoData;
+		var types = DataTable.ext.type.detect;
+		var i, ien, j, jen, k, ken;
+		var col, cell, detectedType, cache;
+	
+		// For each column, spin over the 
+		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
+			col = columns[i];
+			cache = [];
+	
+			if ( ! col.sType && col._sManualType ) {
+				col.sType = col._sManualType;
+			}
+			else if ( ! col.sType ) {
+				for ( j=0, jen=types.length ; j<jen ; j++ ) {
+					for ( k=0, ken=data.length ; k<ken ; k++ ) {
+						// Use a cache array so we only need to get the type data
+						// from the formatter once (when using multiple detectors)
+						if ( cache[k] === undefined ) {
+							cache[k] = _fnGetCellData( settings, k, i, 'type' );
+						}
+	
+						detectedType = types[j]( cache[k], settings );
+	
+						// If null, then this type can't apply to this column, so
+						// rather than testing all cells, break out. There is an
+						// exception for the last type which is `html`. We need to
+						// scan all rows since it is possible to mix string and HTML
+						// types
+						if ( ! detectedType && j !== types.length-1 ) {
+							break;
+						}
+	
+						// Only a single match is needed for html type since it is
+						// bottom of the pile and very similar to string
+						if ( detectedType === 'html' ) {
+							break;
+						}
+					}
+	
+					// Type is valid for all data points in the column - use this
+					// type
+					if ( detectedType ) {
+						col.sType = detectedType;
+						break;
+					}
+				}
+	
+				// Fall back - if no type was detected, always use string
+				if ( ! col.sType ) {
+					col.sType = 'string';
+				}
+			}
+		}
+	}
+	
+	
+	/**
+	 * Take the column definitions and static columns arrays and calculate how
+	 * they relate to column indexes. The callback function will then apply the
+	 * definition found for a column to a suitable configuration object.
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
+	 *  @param {array} aoCols The aoColumns array that defines columns individually
+	 *  @param {function} fn Callback function - takes two parameters, the calculated
+	 *    column index and the definition for that column.
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
+	{
+		var i, iLen, j, jLen, k, kLen, def;
+		var columns = oSettings.aoColumns;
+	
+		// Column definitions with aTargets
+		if ( aoColDefs )
+		{
+			/* Loop over the definitions array - loop in reverse so first instance has priority */
+			for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
+			{
+				def = aoColDefs[i];
+	
+				/* Each definition can target multiple columns, as it is an array */
+				var aTargets = def.targets !== undefined ?
+					def.targets :
+					def.aTargets;
+	
+				if ( ! $.isArray( aTargets ) )
+				{
+					aTargets = [ aTargets ];
+				}
+	
+				for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
+				{
+					if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
+					{
+						/* Add columns that we don't yet know about */
+						while( columns.length <= aTargets[j] )
+						{
+							_fnAddColumn( oSettings );
+						}
+	
+						/* Integer, basic index */
+						fn( aTargets[j], def );
+					}
+					else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
+					{
+						/* Negative integer, right to left column counting */
+						fn( columns.length+aTargets[j], def );
+					}
+					else if ( typeof aTargets[j] === 'string' )
+					{
+						/* Class name matching on TH element */
+						for ( k=0, kLen=columns.length ; k<kLen ; k++ )
+						{
+							if ( aTargets[j] == "_all" ||
+							     $(columns[k].nTh).hasClass( aTargets[j] ) )
+							{
+								fn( k, def );
+							}
+						}
+					}
+				}
+			}
+		}
+	
+		// Statically defined columns array
+		if ( aoCols )
+		{
+			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
+			{
+				fn( i, aoCols[i] );
+			}
+		}
+	}
+	
+	/**
+	 * Add a data array to the table, creating DOM node etc. This is the parallel to
+	 * _fnGatherData, but for adding rows from a Javascript source, rather than a
+	 * DOM source.
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {array} aData data array to be added
+	 *  @param {node} [nTr] TR element to add to the table - optional. If not given,
+	 *    DataTables will create a row automatically
+	 *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
+	 *    if nTr is.
+	 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnAddData ( oSettings, aDataIn, nTr, anTds )
+	{
+		/* Create the object for storing information about this new row */
+		var iRow = oSettings.aoData.length;
+		var oData = $.extend( true, {}, DataTable.models.oRow, {
+			src: nTr ? 'dom' : 'data'
+		} );
+	
+		oData._aData = aDataIn;
+		oSettings.aoData.push( oData );
+	
+		/* Create the cells */
+		var nTd, sThisType;
+		var columns = oSettings.aoColumns;
+		for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
+		{
+			// When working with a row, the data source object must be populated. In
+			// all other cases, the data source object is already populated, so we
+			// don't overwrite it, which might break bindings etc
+			if ( nTr ) {
+				_fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
+			}
+			columns[i].sType = null;
+		}
+	
+		/* Add to the display array */
+		oSettings.aiDisplayMaster.push( iRow );
+	
+		/* Create the DOM information, or register it if already present */
+		if ( nTr || ! oSettings.oFeatures.bDeferRender )
+		{
+			_fnCreateTr( oSettings, iRow, nTr, anTds );
+		}
+	
+		return iRow;
+	}
+	
+	
+	/**
+	 * Add one or more TR elements to the table. Generally we'd expect to
+	 * use this for reading data from a DOM sourced table, but it could be
+	 * used for an TR element. Note that if a TR is given, it is used (i.e.
+	 * it is not cloned).
+	 *  @param {object} settings dataTables settings object
+	 *  @param {array|node|jQuery} trs The TR element(s) to add to the table
+	 *  @returns {array} Array of indexes for the added rows
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnAddTr( settings, trs )
+	{
+		var row;
+	
+		// Allow an individual node to be passed in
+		if ( ! (trs instanceof $) ) {
+			trs = $(trs);
+		}
+	
+		return trs.map( function (i, el) {
+			row = _fnGetRowElements( settings, el );
+			return _fnAddData( settings, row.data, el, row.cells );
+		} );
+	}
+	
+	
+	/**
+	 * Take a TR element and convert it to an index in aoData
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {node} n the TR element to find
+	 *  @returns {int} index if the node is found, null if not
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnNodeToDataIndex( oSettings, n )
+	{
+		return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
+	}
+	
+	
+	/**
+	 * Take a TD element and convert it into a column data index (not the visible index)
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {int} iRow The row number the TD/TH can be found in
+	 *  @param {node} n The TD/TH element to find
+	 *  @returns {int} index if the node is found, -1 if not
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnNodeToColumnIndex( oSettings, iRow, n )
+	{
+		return $.inArray( n, oSettings.aoData[ iRow ].anCells );
+	}
+	
+	
+	/**
+	 * Get the data for a given cell from the internal cache, taking into account data mapping
+	 *  @param {object} settings dataTables settings object
+	 *  @param {int} rowIdx aoData row id
+	 *  @param {int} colIdx Column index
+	 *  @param {string} type data get type ('display', 'type' 'filter' 'sort')
+	 *  @returns {*} Cell data
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnGetCellData( settings, rowIdx, colIdx, type )
+	{
+		var draw           = settings.iDraw;
+		var col            = settings.aoColumns[colIdx];
+		var rowData        = settings.aoData[rowIdx]._aData;
+		var defaultContent = col.sDefaultContent;
+		var cellData       = col.fnGetData( rowData, type, {
+			settings: settings,
+			row:      rowIdx,
+			col:      colIdx
+		} );
+	
+		if ( cellData === undefined ) {
+			if ( settings.iDrawError != draw && defaultContent === null ) {
+				_fnLog( settings, 0, "Requested unknown parameter "+
+					(typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
+					" for row "+rowIdx, 4 );
+				settings.iDrawError = draw;
+			}
+			return defaultContent;
+		}
+	
+		/* When the data source is null, we can use default column data */
+		if ( (cellData === rowData || cellData === null) && defaultContent !== null ) {
+			cellData = defaultContent;
+		}
+		else if ( typeof cellData === 'function' ) {
+			// If the data source is a function, then we run it and use the return,
+			// executing in the scope of the data object (for instances)
+			return cellData.call( rowData );
+		}
+	
+		if ( cellData === null && type == 'display' ) {
+			return '';
+		}
+		return cellData;
+	}
+	
+	
+	/**
+	 * Set the value for a specific cell, into the internal data cache
+	 *  @param {object} settings dataTables settings object
+	 *  @param {int} rowIdx aoData row id
+	 *  @param {int} colIdx Column index
+	 *  @param {*} val Value to set
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnSetCellData( settings, rowIdx, colIdx, val )
+	{
+		var col     = settings.aoColumns[colIdx];
+		var rowData = settings.aoData[rowIdx]._aData;
+	
+		col.fnSetData( rowData, val, {
+			settings: settings,
+			row:      rowIdx,
+			col:      colIdx
+		}  );
+	}
+	
+	
+	// Private variable that is used to match action syntax in the data property object
+	var __reArray = /\[.*?\]$/;
+	var __reFn = /\(\)$/;
+	
+	/**
+	 * Split string on periods, taking into account escaped periods
+	 * @param  {string} str String to split
+	 * @return {array} Split string
+	 */
+	function _fnSplitObjNotation( str )
+	{
+		return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) {
+			return s.replace(/\\./g, '.');
+		} );
+	}
+	
+	
+	/**
+	 * Return a function that can be used to get data from a source object, taking
+	 * into account the ability to use nested objects as a source
+	 *  @param {string|int|function} mSource The data source for the object
+	 *  @returns {function} Data get function
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnGetObjectDataFn( mSource )
+	{
+		if ( $.isPlainObject( mSource ) )
+		{
+			/* Build an object of get functions, and wrap them in a single call */
+			var o = {};
+			$.each( mSource, function (key, val) {
+				if ( val ) {
+					o[key] = _fnGetObjectDataFn( val );
+				}
+			} );
+	
+			return function (data, type, row, meta) {
+				var t = o[type] || o._;
+				return t !== undefined ?
+					t(data, type, row, meta) :
+					data;
+			};
+		}
+		else if ( mSource === null )
+		{
+			/* Give an empty string for rendering / sorting etc */
+			return function (data) { // type, row and meta also passed, but not used
+				return data;
+			};
+		}
+		else if ( typeof mSource === 'function' )
+		{
+			return function (data, type, row, meta) {
+				return mSource( data, type, row, meta );
+			};
+		}
+		else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
+			      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
+		{
+			/* If there is a . in the source string then the data source is in a
+			 * nested object so we loop over the data for each level to get the next
+			 * level down. On each loop we test for undefined, and if found immediately
+			 * return. This allows entire objects to be missing and sDefaultContent to
+			 * be used if defined, rather than throwing an error
+			 */
+			var fetchData = function (data, type, src) {
+				var arrayNotation, funcNotation, out, innerSrc;
+	
+				if ( src !== "" )
+				{
+					var a = _fnSplitObjNotation( src );
+	
+					for ( var i=0, iLen=a.length ; i<iLen ; i++ )
+					{
+						// Check if we are dealing with special notation
+						arrayNotation = a[i].match(__reArray);
+						funcNotation = a[i].match(__reFn);
+	
+						if ( arrayNotation )
+						{
+							// Array notation
+							a[i] = a[i].replace(__reArray, '');
+	
+							// Condition allows simply [] to be passed in
+							if ( a[i] !== "" ) {
+								data = data[ a[i] ];
+							}
+							out = [];
+	
+							// Get the remainder of the nested object to get
+							a.splice( 0, i+1 );
+							innerSrc = a.join('.');
+	
+							// Traverse each entry in the array getting the properties requested
+							for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
+								out.push( fetchData( data[j], type, innerSrc ) );
+							}
+	
+							// If a string is given in between the array notation indicators, that
+							// is used to join the strings together, otherwise an array is returned
+							var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
+							data = (join==="") ? out : out.join(join);
+	
+							// The inner call to fetchData has already traversed through the remainder
+							// of the source requested, so we exit from the loop
+							break;
+						}
+						else if ( funcNotation )
+						{
+							// Function call
+							a[i] = a[i].replace(__reFn, '');
+							data = data[ a[i] ]();
+							continue;
+						}
+	
+						if ( data === null || data[ a[i] ] === undefined )
+						{
+							return undefined;
+						}
+						data = data[ a[i] ];
+					}
+				}
+	
+				return data;
+			};
+	
+			return function (data, type) { // row and meta also passed, but not used
+				return fetchData( data, type, mSource );
+			};
+		}
+		else
+		{
+			/* Array or flat object mapping */
+			return function (data, type) { // row and meta also passed, but not used
+				return data[mSource];
+			};
+		}
+	}
+	
+	
+	/**
+	 * Return a function that can be used to set data from a source object, taking
+	 * into account the ability to use nested objects as a source
+	 *  @param {string|int|function} mSource The data source for the object
+	 *  @returns {function} Data set function
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnSetObjectDataFn( mSource )
+	{
+		if ( $.isPlainObject( mSource ) )
+		{
+			/* Unlike get, only the underscore (global) option is used for for
+			 * setting data since we don't know the type here. This is why an object
+			 * option is not documented for `mData` (which is read/write), but it is
+			 * for `mRender` which is read only.
+			 */
+			return _fnSetObjectDataFn( mSource._ );
+		}
+		else if ( mSource === null )
+		{
+			/* Nothing to do when the data source is null */
+			return function () {};
+		}
+		else if ( typeof mSource === 'function' )
+		{
+			return function (data, val, meta) {
+				mSource( data, 'set', val, meta );
+			};
+		}
+		else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
+			      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
+		{
+			/* Like the get, we need to get data from a nested object */
+			var setData = function (data, val, src) {
+				var a = _fnSplitObjNotation( src ), b;
+				var aLast = a[a.length-1];
+				var arrayNotation, funcNotation, o, innerSrc;
+	
+				for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
+				{
+					// Check if we are dealing with an array notation request
+					arrayNotation = a[i].match(__reArray);
+					funcNotation = a[i].match(__reFn);
+	
+					if ( arrayNotation )
+					{
+						a[i] = a[i].replace(__reArray, '');
+						data[ a[i] ] = [];
+	
+						// Get the remainder of the nested object to set so we can recurse
+						b = a.slice();
+						b.splice( 0, i+1 );
+						innerSrc = b.join('.');
+	
+						// Traverse each entry in the array setting the properties requested
+						for ( var j=0, jLen=val.length ; j<jLen ; j++ )
+						{
+							o = {};
+							setData( o, val[j], innerSrc );
+							data[ a[i] ].push( o );
+						}
+	
+						// The inner call to setData has already traversed through the remainder
+						// of the source and has set the data, thus we can exit here
+						return;
+					}
+					else if ( funcNotation )
+					{
+						// Function call
+						a[i] = a[i].replace(__reFn, '');
+						data = data[ a[i] ]( val );
+					}
+	
+					// If the nested object doesn't currently exist - since we are
+					// trying to set the value - create it
+					if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
+					{
+						data[ a[i] ] = {};
+					}
+					data = data[ a[i] ];
+				}
+	
+				// Last item in the input - i.e, the actual set
+				if ( aLast.match(__reFn ) )
+				{
+					// Function call
+					data = data[ aLast.replace(__reFn, '') ]( val );
+				}
+				else
+				{
+					// If array notation is used, we just want to strip it and use the property name
+					// and assign the value. If it isn't used, then we get the result we want anyway
+					data[ aLast.replace(__reArray, '') ] = val;
+				}
+			};
+	
+			return function (data, val) { // meta is also passed in, but not used
+				return setData( data, val, mSource );
+			};
+		}
+		else
+		{
+			/* Array or flat object mapping */
+			return function (data, val) { // meta is also passed in, but not used
+				data[mSource] = val;
+			};
+		}
+	}
+	
+	
+	/**
+	 * Return an array with the full table data
+	 *  @param {object} oSettings dataTables settings object
+	 *  @returns array {array} aData Master data array
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnGetDataMaster ( settings )
+	{
+		return _pluck( settings.aoData, '_aData' );
+	}
+	
+	
+	/**
+	 * Nuke the table
+	 *  @param {object} oSettings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnClearTable( settings )
+	{
+		settings.aoData.length = 0;
+		settings.aiDisplayMaster.length = 0;
+		settings.aiDisplay.length = 0;
+	}
+	
+	
+	 /**
+	 * Take an array of integers (index array) and remove a target integer (value - not
+	 * the key!)
+	 *  @param {array} a Index array to target
+	 *  @param {int} iTarget value to find
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnDeleteIndex( a, iTarget, splice )
+	{
+		var iTargetIndex = -1;
+	
+		for ( var i=0, iLen=a.length ; i<iLen ; i++ )
+		{
+			if ( a[i] == iTarget )
+			{
+				iTargetIndex = i;
+			}
+			else if ( a[i] > iTarget )
+			{
+				a[i]--;
+			}
+		}
+	
+		if ( iTargetIndex != -1 && splice === undefined )
+		{
+			a.splice( iTargetIndex, 1 );
+		}
+	}
+	
+	
+	/**
+	 * Mark cached data as invalid such that a re-read of the data will occur when
+	 * the cached data is next requested. Also update from the data source object.
+	 *
+	 * @param {object} settings DataTables settings object
+	 * @param {int}    rowIdx   Row index to invalidate
+	 * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
+	 *     or 'data'
+	 * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
+	 *     row will be invalidated
+	 * @memberof DataTable#oApi
+	 *
+	 * @todo For the modularisation of v1.11 this will need to become a callback, so
+	 *   the sort and filter methods can subscribe to it. That will required
+	 *   initialisation options for sorting, which is why it is not already baked in
+	 */
+	function _fnInvalidate( settings, rowIdx, src, colIdx )
+	{
+		var row = settings.aoData[ rowIdx ];
+		var i, ien;
+		var cellWrite = function ( cell, col ) {
+			// This is very frustrating, but in IE if you just write directly
+			// to innerHTML, and elements that are overwritten are GC'ed,
+			// even if there is a reference to them elsewhere
+			while ( cell.childNodes.length ) {
+				cell.removeChild( cell.firstChild );
+			}
+	
+			cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
+		};
+	
+		// Are we reading last data from DOM or the data object?
+		if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
+			// Read the data from the DOM
+			row._aData = _fnGetRowElements(
+					settings, row, colIdx, colIdx === undefined ? undefined : row._aData
+				)
+				.data;
+		}
+		else {
+			// Reading from data object, update the DOM
+			var cells = row.anCells;
+	
+			if ( cells ) {
+				if ( colIdx !== undefined ) {
+					cellWrite( cells[colIdx], colIdx );
+				}
+				else {
+					for ( i=0, ien=cells.length ; i<ien ; i++ ) {
+						cellWrite( cells[i], i );
+					}
+				}
+			}
+		}
+	
+		// For both row and cell invalidation, the cached data for sorting and
+		// filtering is nulled out
+		row._aSortData = null;
+		row._aFilterData = null;
+	
+		// Invalidate the type for a specific column (if given) or all columns since
+		// the data might have changed
+		var cols = settings.aoColumns;
+		if ( colIdx !== undefined ) {
+			cols[ colIdx ].sType = null;
+		}
+		else {
+			for ( i=0, ien=cols.length ; i<ien ; i++ ) {
+				cols[i].sType = null;
+			}
+	
+			// Update DataTables special `DT_*` attributes for the row
+			_fnRowAttributes( row );
+		}
+	}
+	
+	
+	/**
+	 * Build a data source object from an HTML row, reading the contents of the
+	 * cells that are in the row.
+	 *
+	 * @param {object} settings DataTables settings object
+	 * @param {node|object} TR element from which to read data or existing row
+	 *   object from which to re-read the data from the cells
+	 * @param {int} [colIdx] Optional column index
+	 * @param {array|object} [d] Data source object. If `colIdx` is given then this
+	 *   parameter should also be given and will be used to write the data into.
+	 *   Only the column in question will be written
+	 * @returns {object} Object with two parameters: `data` the data read, in
+	 *   document order, and `cells` and array of nodes (they can be useful to the
+	 *   caller, so rather than needing a second traversal to get them, just return
+	 *   them from here).
+	 * @memberof DataTable#oApi
+	 */
+	function _fnGetRowElements( settings, row, colIdx, d )
+	{
+		var
+			tds = [],
+			td = row.firstChild,
+			name, col, o, i=0, contents,
+			columns = settings.aoColumns,
+			objectRead = settings._rowReadObject;
+	
+		// Allow the data object to be passed in, or construct
+		d = d || objectRead ? {} : [];
+	
+		var attr = function ( str, td  ) {
+			if ( typeof str === 'string' ) {
+				var idx = str.indexOf('@');
+	
+				if ( idx !== -1 ) {
+					var attr = str.substring( idx+1 );
+					var setter = _fnSetObjectDataFn( str );
+					setter( d, td.getAttribute( attr ) );
+				}
+			}
+		};
+	
+		// Read data from a cell and store into the data object
+		var cellProcess = function ( cell ) {
+			if ( colIdx === undefined || colIdx === i ) {
+				col = columns[i];
+				contents = $.trim(cell.innerHTML);
+	
+				if ( col && col._bAttrSrc ) {
+					var setter = _fnSetObjectDataFn( col.mData._ );
+					setter( d, contents );
+	
+					attr( col.mData.sort, cell );
+					attr( col.mData.type, cell );
+					attr( col.mData.filter, cell );
+				}
+				else {
+					// Depending on the `data` option for the columns the data can
+					// be read to either an object or an array.
+					if ( objectRead ) {
+						if ( ! col._setter ) {
+							// Cache the setter function
+							col._setter = _fnSetObjectDataFn( col.mData );
+						}
+						col._setter( d, contents );
+					}
+					else {
+						d[i] = contents;
+					}
+				}
+			}
+	
+			i++;
+		};
+	
+		if ( td ) {
+			// `tr` element was passed in
+			while ( td ) {
+				name = td.nodeName.toUpperCase();
+	
+				if ( name == "TD" || name == "TH" ) {
+					cellProcess( td );
+					tds.push( td );
+				}
+	
+				td = td.nextSibling;
+			}
+		}
+		else {
+			// Existing row object passed in
+			tds = row.anCells;
+			
+			for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
+				cellProcess( tds[j] );
+			}
+		}
+	
+		return {
+			data: d,
+			cells: tds
+		};
+	}
+	/**
+	 * Create a new TR element (and it's TD children) for a row
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {int} iRow Row to consider
+	 *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
+	 *    DataTables will create a row automatically
+	 *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
+	 *    if nTr is.
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
+	{
+		var
+			row = oSettings.aoData[iRow],
+			rowData = row._aData,
+			cells = [],
+			nTr, nTd, oCol,
+			i, iLen;
+	
+		if ( row.nTr === null )
+		{
+			nTr = nTrIn || document.createElement('tr');
+	
+			row.nTr = nTr;
+			row.anCells = cells;
+	
+			/* Use a private property on the node to allow reserve mapping from the node
+			 * to the aoData array for fast look up
+			 */
+			nTr._DT_RowIndex = iRow;
+	
+			/* Special parameters can be given by the data source to be used on the row */
+			_fnRowAttributes( row );
+	
+			/* Process each column */
+			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+			{
+				oCol = oSettings.aoColumns[i];
+	
+				nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
+				cells.push( nTd );
+	
+				// Need to create the HTML if new, or if a rendering function is defined
+				if ( !nTrIn || oCol.mRender || oCol.mData !== i )
+				{
+					nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
+				}
+	
+				/* Add user defined class */
+				if ( oCol.sClass )
+				{
+					nTd.className += ' '+oCol.sClass;
+				}
+	
+				// Visibility - add or remove as required
+				if ( oCol.bVisible && ! nTrIn )
+				{
+					nTr.appendChild( nTd );
+				}
+				else if ( ! oCol.bVisible && nTrIn )
+				{
+					nTd.parentNode.removeChild( nTd );
+				}
+	
+				if ( oCol.fnCreatedCell )
+				{
+					oCol.fnCreatedCell.call( oSettings.oInstance,
+						nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
+					);
+				}
+			}
+	
+			_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
+		}
+	
+		// Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
+		// and deployed
+		row.nTr.setAttribute( 'role', 'row' );
+	}
+	
+	
+	/**
+	 * Add attributes to a row based on the special `DT_*` parameters in a data
+	 * source object.
+	 *  @param {object} DataTables row object for the row to be modified
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnRowAttributes( row )
+	{
+		var tr = row.nTr;
+		var data = row._aData;
+	
+		if ( tr ) {
+			if ( data.DT_RowId ) {
+				tr.id = data.DT_RowId;
+			}
+	
+			if ( data.DT_RowClass ) {
+				// Remove any classes added by DT_RowClass before
+				var a = data.DT_RowClass.split(' ');
+				row.__rowc = row.__rowc ?
+					_unique( row.__rowc.concat( a ) ) :
+					a;
+	
+				$(tr)
+					.removeClass( row.__rowc.join(' ') )
+					.addClass( data.DT_RowClass );
+			}
+	
+			if ( data.DT_RowAttr ) {
+				$(tr).attr( data.DT_RowAttr );
+			}
+	
+			if ( data.DT_RowData ) {
+				$(tr).data( data.DT_RowData );
+			}
+		}
+	}
+	
+	
+	/**
+	 * Create the HTML header for the table
+	 *  @param {object} oSettings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnBuildHead( oSettings )
+	{
+		var i, ien, cell, row, column;
+		var thead = oSettings.nTHead;
+		var tfoot = oSettings.nTFoot;
+		var createHeader = $('th, td', thead).length === 0;
+		var classes = oSettings.oClasses;
+		var columns = oSettings.aoColumns;
+	
+		if ( createHeader ) {
+			row = $('<tr/>').appendTo( thead );
+		}
+	
+		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
+			column = columns[i];
+			cell = $( column.nTh ).addClass( column.sClass );
+	
+			if ( createHeader ) {
+				cell.appendTo( row );
+			}
+	
+			// 1.11 move into sorting
+			if ( oSettings.oFeatures.bSort ) {
+				cell.addClass( column.sSortingClass );
+	
+				if ( column.bSortable !== false ) {
+					cell
+						.attr( 'tabindex', oSettings.iTabIndex )
+						.attr( 'aria-controls', oSettings.sTableId );
+	
+					_fnSortAttachListener( oSettings, column.nTh, i );
+				}
+			}
+	
+			if ( column.sTitle != cell.html() ) {
+				cell.html( column.sTitle );
+			}
+	
+			_fnRenderer( oSettings, 'header' )(
+				oSettings, cell, column, classes
+			);
+		}
+	
+		if ( createHeader ) {
+			_fnDetectHeader( oSettings.aoHeader, thead );
+		}
+		
+		/* ARIA role for the rows */
+	 	$(thead).find('>tr').attr('role', 'row');
+	
+		/* Deal with the footer - add classes if required */
+		$(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
+		$(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
+	
+		// Cache the footer cells. Note that we only take the cells from the first
+		// row in the footer. If there is more than one row the user wants to
+		// interact with, they need to use the table().foot() method. Note also this
+		// allows cells to be used for multiple columns using colspan
+		if ( tfoot !== null ) {
+			var cells = oSettings.aoFooter[0];
+	
+			for ( i=0, ien=cells.length ; i<ien ; i++ ) {
+				column = columns[i];
+				column.nTf = cells[i].cell;
+	
+				if ( column.sClass ) {
+					$(column.nTf).addClass( column.sClass );
+				}
+			}
+		}
+	}
+	
+	
+	/**
+	 * Draw the header (or footer) element based on the column visibility states. The
+	 * methodology here is to use the layout array from _fnDetectHeader, modified for
+	 * the instantaneous column visibility, to construct the new layout. The grid is
+	 * traversed over cell at a time in a rows x columns grid fashion, although each
+	 * cell insert can cover multiple elements in the grid - which is tracks using the
+	 * aApplied array. Cell inserts in the grid will only occur where there isn't
+	 * already a cell in that position.
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param array {objects} aoSource Layout array from _fnDetectHeader
+	 *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
+	{
+		var i, iLen, j, jLen, k, kLen, n, nLocalTr;
+		var aoLocal = [];
+		var aApplied = [];
+		var iColumns = oSettings.aoColumns.length;
+		var iRowspan, iColspan;
+	
+		if ( ! aoSource )
+		{
+			return;
+		}
+	
+		if (  bIncludeHidden === undefined )
+		{
+			bIncludeHidden = false;
+		}
+	
+		/* Make a copy of the master layout array, but without the visible columns in it */
+		for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
+		{
+			aoLocal[i] = aoSource[i].slice();
+			aoLocal[i].nTr = aoSource[i].nTr;
+	
+			/* Remove any columns which are currently hidden */
+			for ( j=iColumns-1 ; j>=0 ; j-- )
+			{
+				if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
+				{
+					aoLocal[i].splice( j, 1 );
+				}
+			}
+	
+			/* Prep the applied array - it needs an element for each row */
+			aApplied.push( [] );
+		}
+	
+		for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
+		{
+			nLocalTr = aoLocal[i].nTr;
+	
+			/* All cells are going to be replaced, so empty out the row */
+			if ( nLocalTr )
+			{
+				while( (n = nLocalTr.firstChild) )
+				{
+					nLocalTr.removeChild( n );
+				}
+			}
+	
+			for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
+			{
+				iRowspan = 1;
+				iColspan = 1;
+	
+				/* Check to see if there is already a cell (row/colspan) covering our target
+				 * insert point. If there is, then there is nothing to do.
+				 */
+				if ( aApplied[i][j] === undefined )
+				{
+					nLocalTr.appendChild( aoLocal[i][j].cell );
+					aApplied[i][j] = 1;
+	
+					/* Expand the cell to cover as many rows as needed */
+					while ( aoLocal[i+iRowspan] !== undefined &&
+					        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
+					{
+						aApplied[i+iRowspan][j] = 1;
+						iRowspan++;
+					}
+	
+					/* Expand the cell to cover as many columns as needed */
+					while ( aoLocal[i][j+iColspan] !== undefined &&
+					        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
+					{
+						/* Must update the applied array over the rows for the columns */
+						for ( k=0 ; k<iRowspan ; k++ )
+						{
+							aApplied[i+k][j+iColspan] = 1;
+						}
+						iColspan++;
+					}
+	
+					/* Do the actual expansion in the DOM */
+					$(aoLocal[i][j].cell)
+						.attr('rowspan', iRowspan)
+						.attr('colspan', iColspan);
+				}
+			}
+		}
+	}
+	
+	
+	/**
+	 * Insert the required TR nodes into the table for display
+	 *  @param {object} oSettings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnDraw( oSettings )
+	{
+		/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
+		var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
+		if ( $.inArray( false, aPreDraw ) !== -1 )
+		{
+			_fnProcessingDisplay( oSettings, false );
+			return;
+		}
+	
+		var i, iLen, n;
+		var anRows = [];
+		var iRowCount = 0;
+		var asStripeClasses = oSettings.asStripeClasses;
+		var iStripes = asStripeClasses.length;
+		var iOpenRows = oSettings.aoOpenRows.length;
+		var oLang = oSettings.oLanguage;
+		var iInitDisplayStart = oSettings.iInitDisplayStart;
+		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
+		var aiDisplay = oSettings.aiDisplay;
+	
+		oSettings.bDrawing = true;
+	
+		/* Check and see if we have an initial draw position from state saving */
+		if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
+		{
+			oSettings._iDisplayStart = bServerSide ?
+				iInitDisplayStart :
+				iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
+					0 :
+					iInitDisplayStart;
+	
+			oSettings.iInitDisplayStart = -1;
+		}
+	
+		var iDisplayStart = oSettings._iDisplayStart;
+		var iDisplayEnd = oSettings.fnDisplayEnd();
+	
+		/* Server-side processing draw intercept */
+		if ( oSettings.bDeferLoading )
+		{
+			oSettings.bDeferLoading = false;
+			oSettings.iDraw++;
+			_fnProcessingDisplay( oSettings, false );
+		}
+		else if ( !bServerSide )
+		{
+			oSettings.iDraw++;
+		}
+		else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
+		{
+			return;
+		}
+	
+		if ( aiDisplay.length !== 0 )
+		{
+			var iStart = bServerSide ? 0 : iDisplayStart;
+			var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
+	
+			for ( var j=iStart ; j<iEnd ; j++ )
+			{
+				var iDataIndex = aiDisplay[j];
+				var aoData = oSettings.aoData[ iDataIndex ];
+				if ( aoData.nTr === null )
+				{
+					_fnCreateTr( oSettings, iDataIndex );
+				}
+	
+				var nRow = aoData.nTr;
+	
+				/* Remove the old striping classes and then add the new one */
+				if ( iStripes !== 0 )
+				{
+					var sStripe = asStripeClasses[ iRowCount % iStripes ];
+					if ( aoData._sRowStripe != sStripe )
+					{
+						$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
+						aoData._sRowStripe = sStripe;
+					}
+				}
+	
+				// Row callback functions - might want to manipulate the row
+				// iRowCount and j are not currently documented. Are they at all
+				// useful?
+				_fnCallbackFire( oSettings, 'aoRowCallback', null,
+					[nRow, aoData._aData, iRowCount, j] );
+	
+				anRows.push( nRow );
+				iRowCount++;
+			}
+		}
+		else
+		{
+			/* Table is empty - create a row with an empty message in it */
+			var sZero = oLang.sZeroRecords;
+			if ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )
+			{
+				sZero = oLang.sLoadingRecords;
+			}
+			else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
+			{
+				sZero = oLang.sEmptyTable;
+			}
+	
+			anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
+				.append( $('<td />', {
+					'valign':  'top',
+					'colSpan': _fnVisbleColumns( oSettings ),
+					'class':   oSettings.oClasses.sRowEmpty
+				} ).html( sZero ) )[0];
+		}
+	
+		/* Header and footer callbacks */
+		_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
+			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
+	
+		_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
+			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
+	
+		var body = $(oSettings.nTBody);
+	
+		body.children().detach();
+		body.append( $(anRows) );
+	
+		/* Call all required callback functions for the end of a draw */
+		_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
+	
+		/* Draw is complete, sorting and filtering must be as well */
+		oSettings.bSorted = false;
+		oSettings.bFiltered = false;
+		oSettings.bDrawing = false;
+	}
+	
+	
+	/**
+	 * Redraw the table - taking account of the various features which are enabled
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {boolean} [holdPosition] Keep the current paging position. By default
+	 *    the paging is reset to the first page
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnReDraw( settings, holdPosition )
+	{
+		var
+			features = settings.oFeatures,
+			sort     = features.bSort,
+			filter   = features.bFilter;
+	
+		if ( sort ) {
+			_fnSort( settings );
+		}
+	
+		if ( filter ) {
+			_fnFilterComplete( settings, settings.oPreviousSearch );
+		}
+		else {
+			// No filtering, so we want to just use the display master
+			settings.aiDisplay = settings.aiDisplayMaster.slice();
+		}
+	
+		if ( holdPosition !== true ) {
+			settings._iDisplayStart = 0;
+		}
+	
+		// Let any modules know about the draw hold position state (used by
+		// scrolling internally)
+		settings._drawHold = holdPosition;
+	
+		_fnDraw( settings );
+	
+		settings._drawHold = false;
+	}
+	
+	
+	/**
+	 * Add the options to the page HTML for the table
+	 *  @param {object} oSettings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnAddOptionsHtml ( oSettings )
+	{
+		var classes = oSettings.oClasses;
+		var table = $(oSettings.nTable);
+		var holding = $('<div/>').insertBefore( table ); // Holding element for speed
+		var features = oSettings.oFeatures;
+	
+		// All DataTables are wrapped in a div
+		var insert = $('<div/>', {
+			id:      oSettings.sTableId+'_wrapper',
+			'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
+		} );
+	
+		oSettings.nHolding = holding[0];
+		oSettings.nTableWrapper = insert[0];
+		oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
+	
+		/* Loop over the user set positioning and place the elements as needed */
+		var aDom = oSettings.sDom.split('');
+		var featureNode, cOption, nNewNode, cNext, sAttr, j;
+		for ( var i=0 ; i<aDom.length ; i++ )
+		{
+			featureNode = null;
+			cOption = aDom[i];
+	
+			if ( cOption == '<' )
+			{
+				/* New container div */
+				nNewNode = $('<div/>')[0];
+	
+				/* Check to see if we should append an id and/or a class name to the container */
+				cNext = aDom[i+1];
+				if ( cNext == "'" || cNext == '"' )
+				{
+					sAttr = "";
+					j = 2;
+					while ( aDom[i+j] != cNext )
+					{
+						sAttr += aDom[i+j];
+						j++;
+					}
+	
+					/* Replace jQuery UI constants @todo depreciated */
+					if ( sAttr == "H" )
+					{
+						sAttr = classes.sJUIHeader;
+					}
+					else if ( sAttr == "F" )
+					{
+						sAttr = classes.sJUIFooter;
+					}
+	
+					/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
+					 * breaks the string into parts and applies them as needed
+					 */
+					if ( sAttr.indexOf('.') != -1 )
+					{
+						var aSplit = sAttr.split('.');
+						nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
+						nNewNode.className = aSplit[1];
+					}
+					else if ( sAttr.charAt(0) == "#" )
+					{
+						nNewNode.id = sAttr.substr(1, sAttr.length-1);
+					}
+					else
+					{
+						nNewNode.className = sAttr;
+					}
+	
+					i += j; /* Move along the position array */
+				}
+	
+				insert.append( nNewNode );
+				insert = $(nNewNode);
+			}
+			else if ( cOption == '>' )
+			{
+				/* End container div */
+				insert = insert.parent();
+			}
+			// @todo Move options into their own plugins?
+			else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
+			{
+				/* Length */
+				featureNode = _fnFeatureHtmlLength( oSettings );
+			}
+			else if ( cOption == 'f' && features.bFilter )
+			{
+				/* Filter */
+				featureNode = _fnFeatureHtmlFilter( oSettings );
+			}
+			else if ( cOption == 'r' && features.bProcessing )
+			{
+				/* pRocessing */
+				featureNode = _fnFeatureHtmlProcessing( oSettings );
+			}
+			else if ( cOption == 't' )
+			{
+				/* Table */
+				featureNode = _fnFeatureHtmlTable( oSettings );
+			}
+			else if ( cOption ==  'i' && features.bInfo )
+			{
+				/* Info */
+				featureNode = _fnFeatureHtmlInfo( oSettings );
+			}
+			else if ( cOption == 'p' && features.bPaginate )
+			{
+				/* Pagination */
+				featureNode = _fnFeatureHtmlPaginate( oSettings );
+			}
+			else if ( DataTable.ext.feature.length !== 0 )
+			{
+				/* Plug-in features */
+				var aoFeatures = DataTable.ext.feature;
+				for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
+				{
+					if ( cOption == aoFeatures[k].cFeature )
+					{
+						featureNode = aoFeatures[k].fnInit( oSettings );
+						break;
+					}
+				}
+			}
+	
+			/* Add to the 2D features array */
+			if ( featureNode )
+			{
+				var aanFeatures = oSettings.aanFeatures;
+	
+				if ( ! aanFeatures[cOption] )
+				{
+					aanFeatures[cOption] = [];
+				}
+	
+				aanFeatures[cOption].push( featureNode );
+				insert.append( featureNode );
+			}
+		}
+	
+		/* Built our DOM structure - replace the holding div with what we want */
+		holding.replaceWith( insert );
+	}
+	
+	
+	/**
+	 * Use the DOM source to create up an array of header cells. The idea here is to
+	 * create a layout grid (array) of rows x columns, which contains a reference
+	 * to the cell that that point in the grid (regardless of col/rowspan), such that
+	 * any column / row could be removed and the new grid constructed
+	 *  @param array {object} aLayout Array to store the calculated layout in
+	 *  @param {node} nThead The header/footer element for the table
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnDetectHeader ( aLayout, nThead )
+	{
+		var nTrs = $(nThead).children('tr');
+		var nTr, nCell;
+		var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
+		var bUnique;
+		var fnShiftCol = function ( a, i, j ) {
+			var k = a[i];
+	                while ( k[j] ) {
+				j++;
+			}
+			return j;
+		};
+	
+		aLayout.splice( 0, aLayout.length );
+	
+		/* We know how many rows there are in the layout - so prep it */
+		for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+		{
+			aLayout.push( [] );
+		}
+	
+		/* Calculate a layout array */
+		for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+		{
+			nTr = nTrs[i];
+			iColumn = 0;
+	
+			/* For every cell in the row... */
+			nCell = nTr.firstChild;
+			while ( nCell ) {
+				if ( nCell.nodeName.toUpperCase() == "TD" ||
+				     nCell.nodeName.toUpperCase() == "TH" )
+				{
+					/* Get the col and rowspan attributes from the DOM and sanitise them */
+					iColspan = nCell.getAttribute('colspan') * 1;
+					iRowspan = nCell.getAttribute('rowspan') * 1;
+					iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
+					iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
+	
+					/* There might be colspan cells already in this row, so shift our target
+					 * accordingly
+					 */
+					iColShifted = fnShiftCol( aLayout, i, iColumn );
+	
+					/* Cache calculation for unique columns */
+					bUnique = iColspan === 1 ? true : false;
+	
+					/* If there is col / rowspan, copy the information into the layout grid */
+					for ( l=0 ; l<iColspan ; l++ )
+					{
+						for ( k=0 ; k<iRowspan ; k++ )
+						{
+							aLayout[i+k][iColShifted+l] = {
+								"cell": nCell,
+								"unique": bUnique
+							};
+							aLayout[i+k].nTr = nTr;
+						}
+					}
+				}
+				nCell = nCell.nextSibling;
+			}
+		}
+	}
+	
+	
+	/**
+	 * Get an array of unique th elements, one for each column
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {node} nHeader automatically detect the layout from this node - optional
+	 *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
+	 *  @returns array {node} aReturn list of unique th's
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
+	{
+		var aReturn = [];
+		if ( !aLayout )
+		{
+			aLayout = oSettings.aoHeader;
+			if ( nHeader )
+			{
+				aLayout = [];
+				_fnDetectHeader( aLayout, nHeader );
+			}
+		}
+	
+		for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
+		{
+			for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
+			{
+				if ( aLayout[i][j].unique &&
+					 (!aReturn[j] || !oSettings.bSortCellsTop) )
+				{
+					aReturn[j] = aLayout[i][j].cell;
+				}
+			}
+		}
+	
+		return aReturn;
+	}
+	
+	/**
+	 * Create an Ajax call based on the table's settings, taking into account that
+	 * parameters can have multiple forms, and backwards compatibility.
+	 *
+	 * @param {object} oSettings dataTables settings object
+	 * @param {array} data Data to send to the server, required by
+	 *     DataTables - may be augmented by developer callbacks
+	 * @param {function} fn Callback function to run when data is obtained
+	 */
+	function _fnBuildAjax( oSettings, data, fn )
+	{
+		// Compatibility with 1.9-, allow fnServerData and event to manipulate
+		_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
+	
+		// Convert to object based for 1.10+ if using the old array scheme which can
+		// come from server-side processing or serverParams
+		if ( data && $.isArray(data) ) {
+			var tmp = {};
+			var rbracket = /(.*?)\[\]$/;
+	
+			$.each( data, function (key, val) {
+				var match = val.name.match(rbracket);
+	
+				if ( match ) {
+					// Support for arrays
+					var name = match[0];
+	
+					if ( ! tmp[ name ] ) {
+						tmp[ name ] = [];
+					}
+					tmp[ name ].push( val.value );
+				}
+				else {
+					tmp[val.name] = val.value;
+				}
+			} );
+			data = tmp;
+		}
+	
+		var ajaxData;
+		var ajax = oSettings.ajax;
+		var instance = oSettings.oInstance;
+		var callback = function ( json ) {
+			_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
+			fn( json );
+		};
+	
+		if ( $.isPlainObject( ajax ) && ajax.data )
+		{
+			ajaxData = ajax.data;
+	
+			var newData = $.isFunction( ajaxData ) ?
+				ajaxData( data, oSettings ) :  // fn can manipulate data or return
+				ajaxData;                      // an object object or array to merge
+	
+			// If the function returned something, use that alone
+			data = $.isFunction( ajaxData ) && newData ?
+				newData :
+				$.extend( true, data, newData );
+	
+			// Remove the data property as we've resolved it already and don't want
+			// jQuery to do it again (it is restored at the end of the function)
+			delete ajax.data;
+		}
+	
+		var baseAjax = {
+			"data": data,
+			"success": function (json) {
+				var error = json.error || json.sError;
+				if ( error ) {
+					_fnLog( oSettings, 0, error );
+				}
+	
+				oSettings.json = json;
+				callback( json );
+			},
+			"dataType": "json",
+			"cache": false,
+			"type": oSettings.sServerMethod,
+			"error": function (xhr, error, thrown) {
+				var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
+	
+				if ( $.inArray( true, ret ) === -1 ) {
+					if ( error == "parsererror" ) {
+						_fnLog( oSettings, 0, 'Invalid JSON response', 1 );
+					}
+					else if ( xhr.readyState === 4 ) {
+						_fnLog( oSettings, 0, 'Ajax error', 7 );
+					}
+				}
+	
+				_fnProcessingDisplay( oSettings, false );
+			}
+		};
+	
+		// Store the data submitted for the API
+		oSettings.oAjaxData = data;
+	
+		// Allow plug-ins and external processes to modify the data
+		_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
+	
+		if ( oSettings.fnServerData )
+		{
+			// DataTables 1.9- compatibility
+			oSettings.fnServerData.call( instance,
+				oSettings.sAjaxSource,
+				$.map( data, function (val, key) { // Need to convert back to 1.9 trad format
+					return { name: key, value: val };
+				} ),
+				callback,
+				oSettings
+			);
+		}
+		else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
+		{
+			// DataTables 1.9- compatibility
+			oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
+				url: ajax || oSettings.sAjaxSource
+			} ) );
+		}
+		else if ( $.isFunction( ajax ) )
+		{
+			// Is a function - let the caller define what needs to be done
+			oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
+		}
+		else
+		{
+			// Object to extend the base settings
+			oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
+	
+			// Restore for next time around
+			ajax.data = ajaxData;
+		}
+	}
+	
+	
+	/**
+	 * Update the table using an Ajax call
+	 *  @param {object} settings dataTables settings object
+	 *  @returns {boolean} Block the table drawing or not
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnAjaxUpdate( settings )
+	{
+		if ( settings.bAjaxDataGet ) {
+			settings.iDraw++;
+			_fnProcessingDisplay( settings, true );
+	
+			_fnBuildAjax(
+				settings,
+				_fnAjaxParameters( settings ),
+				function(json) {
+					_fnAjaxUpdateDraw( settings, json );
+				}
+			);
+	
+			return false;
+		}
+		return true;
+	}
+	
+	
+	/**
+	 * Build up the parameters in an object needed for a server-side processing
+	 * request. Note that this is basically done twice, is different ways - a modern
+	 * method which is used by default in DataTables 1.10 which uses objects and
+	 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
+	 * the sAjaxSource option is used in the initialisation, or the legacyAjax
+	 * option is set.
+	 *  @param {object} oSettings dataTables settings object
+	 *  @returns {bool} block the table drawing or not
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnAjaxParameters( settings )
+	{
+		var
+			columns = settings.aoColumns,
+			columnCount = columns.length,
+			features = settings.oFeatures,
+			preSearch = settings.oPreviousSearch,
+			preColSearch = settings.aoPreSearchCols,
+			i, data = [], dataProp, column, columnSearch,
+			sort = _fnSortFlatten( settings ),
+			displayStart = settings._iDisplayStart,
+			displayLength = features.bPaginate !== false ?
+				settings._iDisplayLength :
+				-1;
+	
+		var param = function ( name, value ) {
+			data.push( { 'name': name, 'value': value } );
+		};
+	
+		// DataTables 1.9- compatible method
+		param( 'sEcho',          settings.iDraw );
+		param( 'iColumns',       columnCount );
+		param( 'sColumns',       _pluck( columns, 'sName' ).join(',') );
+		param( 'iDisplayStart',  displayStart );
+		param( 'iDisplayLength', displayLength );
+	
+		// DataTables 1.10+ method
+		var d = {
+			draw:    settings.iDraw,
+			columns: [],
+			order:   [],
+			start:   displayStart,
+			length:  displayLength,
+			search:  {
+				value: preSearch.sSearch,
+				regex: preSearch.bRegex
+			}
+		};
+	
+		for ( i=0 ; i<columnCount ; i++ ) {
+			column = columns[i];
+			columnSearch = preColSearch[i];
+			dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
+	
+			d.columns.push( {
+				data:       dataProp,
+				name:       column.sName,
+				searchable: column.bSearchable,
+				orderable:  column.bSortable,
+				search:     {
+					value: columnSearch.sSearch,
+					regex: columnSearch.bRegex
+				}
+			} );
+	
+			param( "mDataProp_"+i, dataProp );
+	
+			if ( features.bFilter ) {
+				param( 'sSearch_'+i,     columnSearch.sSearch );
+				param( 'bRegex_'+i,      columnSearch.bRegex );
+				param( 'bSearchable_'+i, column.bSearchable );
+			}
+	
+			if ( features.bSort ) {
+				param( 'bSortable_'+i, column.bSortable );
+			}
+		}
+	
+		if ( features.bFilter ) {
+			param( 'sSearch', preSearch.sSearch );
+			param( 'bRegex', preSearch.bRegex );
+		}
+	
+		if ( features.bSort ) {
+			$.each( sort, function ( i, val ) {
+				d.order.push( { column: val.col, dir: val.dir } );
+	
+				param( 'iSortCol_'+i, val.col );
+				param( 'sSortDir_'+i, val.dir );
+			} );
+	
+			param( 'iSortingCols', sort.length );
+		}
+	
+		// If the legacy.ajax parameter is null, then we automatically decide which
+		// form to use, based on sAjaxSource
+		var legacy = DataTable.ext.legacy.ajax;
+		if ( legacy === null ) {
+			return settings.sAjaxSource ? data : d;
+		}
+	
+		// Otherwise, if legacy has been specified then we use that to decide on the
+		// form
+		return legacy ? data : d;
+	}
+	
+	
+	/**
+	 * Data the data from the server (nuking the old) and redraw the table
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {object} json json data return from the server.
+	 *  @param {string} json.sEcho Tracking flag for DataTables to match requests
+	 *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
+	 *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
+	 *  @param {array} json.aaData The data to display on this page
+	 *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnAjaxUpdateDraw ( settings, json )
+	{
+		// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
+		// Support both
+		var compat = function ( old, modern ) {
+			return json[old] !== undefined ? json[old] : json[modern];
+		};
+	
+		var data = _fnAjaxDataSrc( settings, json );
+		var draw            = compat( 'sEcho',                'draw' );
+		var recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );
+		var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
+	
+		if ( draw ) {
+			// Protect against out of sequence returns
+			if ( draw*1 < settings.iDraw ) {
+				return;
+			}
+			settings.iDraw = draw * 1;
+		}
+	
+		_fnClearTable( settings );
+		settings._iRecordsTotal   = parseInt(recordsTotal, 10);
+		settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
+	
+		for ( var i=0, ien=data.length ; i<ien ; i++ ) {
+			_fnAddData( settings, data[i] );
+		}
+		settings.aiDisplay = settings.aiDisplayMaster.slice();
+	
+		settings.bAjaxDataGet = false;
+		_fnDraw( settings );
+	
+		if ( ! settings._bInitComplete ) {
+			_fnInitComplete( settings, json );
+		}
+	
+		settings.bAjaxDataGet = true;
+		_fnProcessingDisplay( settings, false );
+	}
+	
+	
+	/**
+	 * Get the data from the JSON data source to use for drawing a table. Using
+	 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
+	 * source object, or from a processing function.
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param  {object} json Data source object / array from the server
+	 *  @return {array} Array of data to use
+	 */
+	function _fnAjaxDataSrc ( oSettings, json )
+	{
+		var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
+			oSettings.ajax.dataSrc :
+			oSettings.sAjaxDataProp; // Compatibility with 1.9-.
+	
+		// Compatibility with 1.9-. In order to read from aaData, check if the
+		// default has been changed, if not, check for aaData
+		if ( dataSrc === 'data' ) {
+			return json.aaData || json[dataSrc];
+		}
+	
+		return dataSrc !== "" ?
+			_fnGetObjectDataFn( dataSrc )( json ) :
+			json;
+	}
+	
+	/**
+	 * Generate the node required for filtering text
+	 *  @returns {node} Filter control element
+	 *  @param {object} oSettings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnFeatureHtmlFilter ( settings )
+	{
+		var classes = settings.oClasses;
+		var tableId = settings.sTableId;
+		var language = settings.oLanguage;
+		var previousSearch = settings.oPreviousSearch;
+		var features = settings.aanFeatures;
+		var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
+	
+		var str = language.sSearch;
+		str = str.match(/_INPUT_/) ?
+			str.replace('_INPUT_', input) :
+			str+input;
+	
+		var filter = $('<div/>', {
+				'id': ! features.f ? tableId+'_filter' : null,
+				'class': classes.sFilter
+			} )
+			.append( $('<label/>' ).append( str ) );
+	
+		var searchFn = function() {
+			/* Update all other filter input elements for the new display */
+			var n = features.f;
+			var val = !this.value ? "" : this.value; // mental IE8 fix :-(
+	
+			/* Now do the filter */
+			if ( val != previousSearch.sSearch ) {
+				_fnFilterComplete( settings, {
+					"sSearch": val,
+					"bRegex": previousSearch.bRegex,
+					"bSmart": previousSearch.bSmart ,
+					"bCaseInsensitive": previousSearch.bCaseInsensitive
+				} );
+	
+				// Need to redraw, without resorting
+				settings._iDisplayStart = 0;
+				_fnDraw( settings );
+			}
+		};
+	
+		var searchDelay = settings.searchDelay !== null ?
+			settings.searchDelay :
+			_fnDataSource( settings ) === 'ssp' ?
+				400 :
+				0;
+	
+		var jqFilter = $('input', filter)
+			.val( previousSearch.sSearch )
+			.attr( 'placeholder', language.sSearchPlaceholder )
+			.bind(
+				'keyup.DT search.DT input.DT paste.DT cut.DT',
+				searchDelay ?
+					_fnThrottle( searchFn, searchDelay ) :
+					searchFn
+			)
+			.bind( 'keypress.DT', function(e) {
+				/* Prevent form submission */
+				if ( e.keyCode == 13 ) {
+					return false;
+				}
+			} )
+			.attr('aria-controls', tableId);
+	
+		// Update the input elements whenever the table is filtered
+		$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
+			if ( settings === s ) {
+				// IE9 throws an 'unknown error' if document.activeElement is used
+				// inside an iframe or frame...
+				try {
+					if ( jqFilter[0] !== document.activeElement ) {
+						jqFilter.val( previousSearch.sSearch );
+					}
+				}
+				catch ( e ) {}
+			}
+		} );
+	
+		return filter[0];
+	}
+	
+	
+	/**
+	 * Filter the table using both the global filter and column based filtering
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {object} oSearch search information
+	 *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnFilterComplete ( oSettings, oInput, iForce )
+	{
+		var oPrevSearch = oSettings.oPreviousSearch;
+		var aoPrevSearch = oSettings.aoPreSearchCols;
+		var fnSaveFilter = function ( oFilter ) {
+			/* Save the filtering values */
+			oPrevSearch.sSearch = oFilter.sSearch;
+			oPrevSearch.bRegex = oFilter.bRegex;
+			oPrevSearch.bSmart = oFilter.bSmart;
+			oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
+		};
+		var fnRegex = function ( o ) {
+			// Backwards compatibility with the bEscapeRegex option
+			return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
+		};
+	
+		// Resolve any column types that are unknown due to addition or invalidation
+		// @todo As per sort - can this be moved into an event handler?
+		_fnColumnTypes( oSettings );
+	
+		/* In server-side processing all filtering is done by the server, so no point hanging around here */
+		if ( _fnDataSource( oSettings ) != 'ssp' )
+		{
+			/* Global filter */
+			_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
+			fnSaveFilter( oInput );
+	
+			/* Now do the individual column filter */
+			for ( var i=0 ; i<aoPrevSearch.length ; i++ )
+			{
+				_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
+					aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
+			}
+	
+			/* Custom filtering */
+			_fnFilterCustom( oSettings );
+		}
+		else
+		{
+			fnSaveFilter( oInput );
+		}
+	
+		/* Tell the draw function we have been filtering */
+		oSettings.bFiltered = true;
+		_fnCallbackFire( oSettings, null, 'search', [oSettings] );
+	}
+	
+	
+	/**
+	 * Apply custom filtering functions
+	 *  @param {object} oSettings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnFilterCustom( settings )
+	{
+		var filters = DataTable.ext.search;
+		var displayRows = settings.aiDisplay;
+		var row, rowIdx;
+	
+		for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
+			var rows = [];
+	
+			// Loop over each row and see if it should be included
+			for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
+				rowIdx = displayRows[ j ];
+				row = settings.aoData[ rowIdx ];
+	
+				if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
+					rows.push( rowIdx );
+				}
+			}
+	
+			// So the array reference doesn't break set the results into the
+			// existing array
+			displayRows.length = 0;
+			displayRows.push.apply( displayRows, rows );
+		}
+	}
+	
+	
+	/**
+	 * Filter the table on a per-column basis
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {string} sInput string to filter on
+	 *  @param {int} iColumn column to filter
+	 *  @param {bool} bRegex treat search string as a regular expression or not
+	 *  @param {bool} bSmart use smart filtering or not
+	 *  @param {bool} bCaseInsensitive Do case insenstive matching or not
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
+	{
+		if ( searchStr === '' ) {
+			return;
+		}
+	
+		var data;
+		var display = settings.aiDisplay;
+		var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
+	
+		for ( var i=display.length-1 ; i>=0 ; i-- ) {
+			data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
+	
+			if ( ! rpSearch.test( data ) ) {
+				display.splice( i, 1 );
+			}
+		}
+	}
+	
+	
+	/**
+	 * Filter the data table based on user input and draw the table
+	 *  @param {object} settings dataTables settings object
+	 *  @param {string} input string to filter on
+	 *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
+	 *  @param {bool} regex treat as a regular expression or not
+	 *  @param {bool} smart perform smart filtering or not
+	 *  @param {bool} caseInsensitive Do case insenstive matching or not
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
+	{
+		var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
+		var prevSearch = settings.oPreviousSearch.sSearch;
+		var displayMaster = settings.aiDisplayMaster;
+		var display, invalidated, i;
+	
+		// Need to take account of custom filtering functions - always filter
+		if ( DataTable.ext.search.length !== 0 ) {
+			force = true;
+		}
+	
+		// Check if any of the rows were invalidated
+		invalidated = _fnFilterData( settings );
+	
+		// If the input is blank - we just want the full data set
+		if ( input.length <= 0 ) {
+			settings.aiDisplay = displayMaster.slice();
+		}
+		else {
+			// New search - start from the master array
+			if ( invalidated ||
+				 force ||
+				 prevSearch.length > input.length ||
+				 input.indexOf(prevSearch) !== 0 ||
+				 settings.bSorted // On resort, the display master needs to be
+				                  // re-filtered since indexes will have changed
+			) {
+				settings.aiDisplay = displayMaster.slice();
+			}
+	
+			// Search the display array
+			display = settings.aiDisplay;
+	
+			for ( i=display.length-1 ; i>=0 ; i-- ) {
+				if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
+					display.splice( i, 1 );
+				}
+			}
+		}
+	}
+	
+	
+	/**
+	 * Build a regular expression object suitable for searching a table
+	 *  @param {string} sSearch string to search for
+	 *  @param {bool} bRegex treat as a regular expression or not
+	 *  @param {bool} bSmart perform smart filtering or not
+	 *  @param {bool} bCaseInsensitive Do case insensitive matching or not
+	 *  @returns {RegExp} constructed object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
+	{
+		search = regex ?
+			search :
+			_fnEscapeRegex( search );
+		
+		if ( smart ) {
+			/* For smart filtering we want to allow the search to work regardless of
+			 * word order. We also want double quoted text to be preserved, so word
+			 * order is important - a la google. So this is what we want to
+			 * generate:
+			 * 
+			 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
+			 */
+			var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
+				if ( word.charAt(0) === '"' ) {
+					var m = word.match( /^"(.*)"$/ );
+					word = m ? m[1] : word;
+				}
+	
+				return word.replace('"', '');
+			} );
+	
+			search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
+		}
+	
+		return new RegExp( search, caseInsensitive ? 'i' : '' );
+	}
+	
+	
+	/**
+	 * Escape a string such that it can be used in a regular expression
+	 *  @param {string} sVal string to escape
+	 *  @returns {string} escaped string
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnEscapeRegex ( sVal )
+	{
+		return sVal.replace( _re_escape_regex, '\\$1' );
+	}
+	
+	
+	
+	var __filter_div = $('<div>')[0];
+	var __filter_div_textContent = __filter_div.textContent !== undefined;
+	
+	// Update the filtering data for each row if needed (by invalidation or first run)
+	function _fnFilterData ( settings )
+	{
+		var columns = settings.aoColumns;
+		var column;
+		var i, j, ien, jen, filterData, cellData, row;
+		var fomatters = DataTable.ext.type.search;
+		var wasInvalidated = false;
+	
+		for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
+			row = settings.aoData[i];
+	
+			if ( ! row._aFilterData ) {
+				filterData = [];
+	
+				for ( j=0, jen=columns.length ; j<jen ; j++ ) {
+					column = columns[j];
+	
+					if ( column.bSearchable ) {
+						cellData = _fnGetCellData( settings, i, j, 'filter' );
+	
+						if ( fomatters[ column.sType ] ) {
+							cellData = fomatters[ column.sType ]( cellData );
+						}
+	
+						// Search in DataTables 1.10 is string based. In 1.11 this
+						// should be altered to also allow strict type checking.
+						if ( cellData === null ) {
+							cellData = '';
+						}
+	
+						if ( typeof cellData !== 'string' && cellData.toString ) {
+							cellData = cellData.toString();
+						}
+					}
+					else {
+						cellData = '';
+					}
+	
+					// If it looks like there is an HTML entity in the string,
+					// attempt to decode it so sorting works as expected. Note that
+					// we could use a single line of jQuery to do this, but the DOM
+					// method used here is much faster http://jsperf.com/html-decode
+					if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
+						__filter_div.innerHTML = cellData;
+						cellData = __filter_div_textContent ?
+							__filter_div.textContent :
+							__filter_div.innerText;
+					}
+	
+					if ( cellData.replace ) {
+						cellData = cellData.replace(/[\r\n]/g, '');
+					}
+	
+					filterData.push( cellData );
+				}
+	
+				row._aFilterData = filterData;
+				row._sFilterRow = filterData.join('  ');
+				wasInvalidated = true;
+			}
+		}
+	
+		return wasInvalidated;
+	}
+	
+	
+	/**
+	 * Convert from the internal Hungarian notation to camelCase for external
+	 * interaction
+	 *  @param {object} obj Object to convert
+	 *  @returns {object} Inverted object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnSearchToCamel ( obj )
+	{
+		return {
+			search:          obj.sSearch,
+			smart:           obj.bSmart,
+			regex:           obj.bRegex,
+			caseInsensitive: obj.bCaseInsensitive
+		};
+	}
+	
+	
+	
+	/**
+	 * Convert from camelCase notation to the internal Hungarian. We could use the
+	 * Hungarian convert function here, but this is cleaner
+	 *  @param {object} obj Object to convert
+	 *  @returns {object} Inverted object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnSearchToHung ( obj )
+	{
+		return {
+			sSearch:          obj.search,
+			bSmart:           obj.smart,
+			bRegex:           obj.regex,
+			bCaseInsensitive: obj.caseInsensitive
+		};
+	}
+	
+	/**
+	 * Generate the node required for the info display
+	 *  @param {object} oSettings dataTables settings object
+	 *  @returns {node} Information element
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnFeatureHtmlInfo ( settings )
+	{
+		var
+			tid = settings.sTableId,
+			nodes = settings.aanFeatures.i,
+			n = $('<div/>', {
+				'class': settings.oClasses.sInfo,
+				'id': ! nodes ? tid+'_info' : null
+			} );
+	
+		if ( ! nodes ) {
+			// Update display on each draw
+			settings.aoDrawCallback.push( {
+				"fn": _fnUpdateInfo,
+				"sName": "information"
+			} );
+	
+			n
+				.attr( 'role', 'status' )
+				.attr( 'aria-live', 'polite' );
+	
+			// Table is described by our info div
+			$(settings.nTable).attr( 'aria-describedby', tid+'_info' );
+		}
+	
+		return n[0];
+	}
+	
+	
+	/**
+	 * Update the information elements in the display
+	 *  @param {object} settings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnUpdateInfo ( settings )
+	{
+		/* Show information about the table */
+		var nodes = settings.aanFeatures.i;
+		if ( nodes.length === 0 ) {
+			return;
+		}
+	
+		var
+			lang  = settings.oLanguage,
+			start = settings._iDisplayStart+1,
+			end   = settings.fnDisplayEnd(),
+			max   = settings.fnRecordsTotal(),
+			total = settings.fnRecordsDisplay(),
+			out   = total ?
+				lang.sInfo :
+				lang.sInfoEmpty;
+	
+		if ( total !== max ) {
+			/* Record set after filtering */
+			out += ' ' + lang.sInfoFiltered;
+		}
+	
+		// Convert the macros
+		out += lang.sInfoPostFix;
+		out = _fnInfoMacros( settings, out );
+	
+		var callback = lang.fnInfoCallback;
+		if ( callback !== null ) {
+			out = callback.call( settings.oInstance,
+				settings, start, end, max, total, out
+			);
+		}
+	
+		$(nodes).html( out );
+	}
+	
+	
+	function _fnInfoMacros ( settings, str )
+	{
+		// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
+		// internally
+		var
+			formatter  = settings.fnFormatNumber,
+			start      = settings._iDisplayStart+1,
+			len        = settings._iDisplayLength,
+			vis        = settings.fnRecordsDisplay(),
+			all        = len === -1;
+	
+		return str.
+			replace(/_START_/g, formatter.call( settings, start ) ).
+			replace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).
+			replace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).
+			replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
+			replace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
+			replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
+	}
+	
+	
+	
+	/**
+	 * Draw the table for the first time, adding all required features
+	 *  @param {object} settings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnInitialise ( settings )
+	{
+		var i, iLen, iAjaxStart=settings.iInitDisplayStart;
+		var columns = settings.aoColumns, column;
+		var features = settings.oFeatures;
+	
+		/* Ensure that the table data is fully initialised */
+		if ( ! settings.bInitialised ) {
+			setTimeout( function(){ _fnInitialise( settings ); }, 200 );
+			return;
+		}
+	
+		/* Show the display HTML options */
+		_fnAddOptionsHtml( settings );
+	
+		/* Build and draw the header / footer for the table */
+		_fnBuildHead( settings );
+		_fnDrawHead( settings, settings.aoHeader );
+		_fnDrawHead( settings, settings.aoFooter );
+	
+		/* Okay to show that something is going on now */
+		_fnProcessingDisplay( settings, true );
+	
+		/* Calculate sizes for columns */
+		if ( features.bAutoWidth ) {
+			_fnCalculateColumnWidths( settings );
+		}
+	
+		for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
+			column = columns[i];
+	
+			if ( column.sWidth ) {
+				column.nTh.style.width = _fnStringToCss( column.sWidth );
+			}
+		}
+	
+		// If there is default sorting required - let's do it. The sort function
+		// will do the drawing for us. Otherwise we draw the table regardless of the
+		// Ajax source - this allows the table to look initialised for Ajax sourcing
+		// data (show 'loading' message possibly)
+		_fnReDraw( settings );
+	
+		// Server-side processing init complete is done by _fnAjaxUpdateDraw
+		var dataSrc = _fnDataSource( settings );
+		if ( dataSrc != 'ssp' ) {
+			// if there is an ajax source load the data
+			if ( dataSrc == 'ajax' ) {
+				_fnBuildAjax( settings, [], function(json) {
+					var aData = _fnAjaxDataSrc( settings, json );
+	
+					// Got the data - add it to the table
+					for ( i=0 ; i<aData.length ; i++ ) {
+						_fnAddData( settings, aData[i] );
+					}
+	
+					// Reset the init display for cookie saving. We've already done
+					// a filter, and therefore cleared it before. So we need to make
+					// it appear 'fresh'
+					settings.iInitDisplayStart = iAjaxStart;
+	
+					_fnReDraw( settings );
+	
+					_fnProcessingDisplay( settings, false );
+					_fnInitComplete( settings, json );
+				}, settings );
+			}
+			else {
+				_fnProcessingDisplay( settings, false );
+				_fnInitComplete( settings );
+			}
+		}
+	}
+	
+	
+	/**
+	 * Draw the table for the first time, adding all required features
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {object} [json] JSON from the server that completed the table, if using Ajax source
+	 *    with client-side processing (optional)
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnInitComplete ( settings, json )
+	{
+		settings._bInitComplete = true;
+	
+		// On an Ajax load we now have data and therefore want to apply the column
+		// sizing
+		if ( json ) {
+			_fnAdjustColumnSizing( settings );
+		}
+	
+		_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
+	}
+	
+	
+	function _fnLengthChange ( settings, val )
+	{
+		var len = parseInt( val, 10 );
+		settings._iDisplayLength = len;
+	
+		_fnLengthOverflow( settings );
+	
+		// Fire length change event
+		_fnCallbackFire( settings, null, 'length', [settings, len] );
+	}
+	
+	
+	/**
+	 * Generate the node required for user display length changing
+	 *  @param {object} settings dataTables settings object
+	 *  @returns {node} Display length feature node
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnFeatureHtmlLength ( settings )
+	{
+		var
+			classes  = settings.oClasses,
+			tableId  = settings.sTableId,
+			menu     = settings.aLengthMenu,
+			d2       = $.isArray( menu[0] ),
+			lengths  = d2 ? menu[0] : menu,
+			language = d2 ? menu[1] : menu;
+	
+		var select = $('<select/>', {
+			'name':          tableId+'_length',
+			'aria-controls': tableId,
+			'class':         classes.sLengthSelect
+		} );
+	
+		for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
+			select[0][ i ] = new Option( language[i], lengths[i] );
+		}
+	
+		var div = $('<div><label/></div>').addClass( classes.sLength );
+		if ( ! settings.aanFeatures.l ) {
+			div[0].id = tableId+'_length';
+		}
+	
+		div.children().append(
+			settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
+		);
+	
+		// Can't use `select` variable as user might provide their own and the
+		// reference is broken by the use of outerHTML
+		$('select', div)
+			.val( settings._iDisplayLength )
+			.bind( 'change.DT', function(e) {
+				_fnLengthChange( settings, $(this).val() );
+				_fnDraw( settings );
+			} );
+	
+		// Update node value whenever anything changes the table's length
+		$(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
+			if ( settings === s ) {
+				$('select', div).val( len );
+			}
+		} );
+	
+		return div[0];
+	}
+	
+	
+	
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Note that most of the paging logic is done in
+	 * DataTable.ext.pager
+	 */
+	
+	/**
+	 * Generate the node required for default pagination
+	 *  @param {object} oSettings dataTables settings object
+	 *  @returns {node} Pagination feature node
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnFeatureHtmlPaginate ( settings )
+	{
+		var
+			type   = settings.sPaginationType,
+			plugin = DataTable.ext.pager[ type ],
+			modern = typeof plugin === 'function',
+			redraw = function( settings ) {
+				_fnDraw( settings );
+			},
+			node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
+			features = settings.aanFeatures;
+	
+		if ( ! modern ) {
+			plugin.fnInit( settings, node, redraw );
+		}
+	
+		/* Add a draw callback for the pagination on first instance, to update the paging display */
+		if ( ! features.p )
+		{
+			node.id = settings.sTableId+'_paginate';
+	
+			settings.aoDrawCallback.push( {
+				"fn": function( settings ) {
+					if ( modern ) {
+						var
+							start      = settings._iDisplayStart,
+							len        = settings._iDisplayLength,
+							visRecords = settings.fnRecordsDisplay(),
+							all        = len === -1,
+							page = all ? 0 : Math.ceil( start / len ),
+							pages = all ? 1 : Math.ceil( visRecords / len ),
+							buttons = plugin(page, pages),
+							i, ien;
+	
+						for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
+							_fnRenderer( settings, 'pageButton' )(
+								settings, features.p[i], i, buttons, page, pages
+							);
+						}
+					}
+					else {
+						plugin.fnUpdate( settings, redraw );
+					}
+				},
+				"sName": "pagination"
+			} );
+		}
+	
+		return node;
+	}
+	
+	
+	/**
+	 * Alter the display settings to change the page
+	 *  @param {object} settings DataTables settings object
+	 *  @param {string|int} action Paging action to take: "first", "previous",
+	 *    "next" or "last" or page number to jump to (integer)
+	 *  @param [bool] redraw Automatically draw the update or not
+	 *  @returns {bool} true page has changed, false - no change
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnPageChange ( settings, action, redraw )
+	{
+		var
+			start     = settings._iDisplayStart,
+			len       = settings._iDisplayLength,
+			records   = settings.fnRecordsDisplay();
+	
+		if ( records === 0 || len === -1 )
+		{
+			start = 0;
+		}
+		else if ( typeof action === "number" )
+		{
+			start = action * len;
+	
+			if ( start > records )
+			{
+				start = 0;
+			}
+		}
+		else if ( action == "first" )
+		{
+			start = 0;
+		}
+		else if ( action == "previous" )
+		{
+			start = len >= 0 ?
+				start - len :
+				0;
+	
+			if ( start < 0 )
+			{
+			  start = 0;
+			}
+		}
+		else if ( action == "next" )
+		{
+			if ( start + len < records )
+			{
+				start += len;
+			}
+		}
+		else if ( action == "last" )
+		{
+			start = Math.floor( (records-1) / len) * len;
+		}
+		else
+		{
+			_fnLog( settings, 0, "Unknown paging action: "+action, 5 );
+		}
+	
+		var changed = settings._iDisplayStart !== start;
+		settings._iDisplayStart = start;
+	
+		if ( changed ) {
+			_fnCallbackFire( settings, null, 'page', [settings] );
+	
+			if ( redraw ) {
+				_fnDraw( settings );
+			}
+		}
+	
+		return changed;
+	}
+	
+	
+	
+	/**
+	 * Generate the node required for the processing node
+	 *  @param {object} settings dataTables settings object
+	 *  @returns {node} Processing element
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnFeatureHtmlProcessing ( settings )
+	{
+		return $('<div/>', {
+				'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
+				'class': settings.oClasses.sProcessing
+			} )
+			.html( settings.oLanguage.sProcessing )
+			.insertBefore( settings.nTable )[0];
+	}
+	
+	
+	/**
+	 * Display or hide the processing indicator
+	 *  @param {object} settings dataTables settings object
+	 *  @param {bool} show Show the processing indicator (true) or not (false)
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnProcessingDisplay ( settings, show )
+	{
+		if ( settings.oFeatures.bProcessing ) {
+			$(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
+		}
+	
+		_fnCallbackFire( settings, null, 'processing', [settings, show] );
+	}
+	
+	/**
+	 * Add any control elements for the table - specifically scrolling
+	 *  @param {object} settings dataTables settings object
+	 *  @returns {node} Node to add to the DOM
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnFeatureHtmlTable ( settings )
+	{
+		var table = $(settings.nTable);
+	
+		// Add the ARIA grid role to the table
+		table.attr( 'role', 'grid' );
+	
+		// Scrolling from here on in
+		var scroll = settings.oScroll;
+	
+		if ( scroll.sX === '' && scroll.sY === '' ) {
+			return settings.nTable;
+		}
+	
+		var scrollX = scroll.sX;
+		var scrollY = scroll.sY;
+		var classes = settings.oClasses;
+		var caption = table.children('caption');
+		var captionSide = caption.length ? caption[0]._captionSide : null;
+		var headerClone = $( table[0].cloneNode(false) );
+		var footerClone = $( table[0].cloneNode(false) );
+		var footer = table.children('tfoot');
+		var _div = '<div/>';
+		var size = function ( s ) {
+			return !s ? null : _fnStringToCss( s );
+		};
+	
+		// This is fairly messy, but with x scrolling enabled, if the table has a
+		// width attribute, regardless of any width applied using the column width
+		// options, the browser will shrink or grow the table as needed to fit into
+		// that 100%. That would make the width options useless. So we remove it.
+		// This is okay, under the assumption that width:100% is applied to the
+		// table in CSS (it is in the default stylesheet) which will set the table
+		// width as appropriate (the attribute and css behave differently...)
+		if ( scroll.sX && table.attr('width') === '100%' ) {
+			table.removeAttr('width');
+		}
+	
+		if ( ! footer.length ) {
+			footer = null;
+		}
+	
+		/*
+		 * The HTML structure that we want to generate in this function is:
+		 *  div - scroller
+		 *    div - scroll head
+		 *      div - scroll head inner
+		 *        table - scroll head table
+		 *          thead - thead
+		 *    div - scroll body
+		 *      table - table (master table)
+		 *        thead - thead clone for sizing
+		 *        tbody - tbody
+		 *    div - scroll foot
+		 *      div - scroll foot inner
+		 *        table - scroll foot table
+		 *          tfoot - tfoot
+		 */
+		var scroller = $( _div, { 'class': classes.sScrollWrapper } )
+			.append(
+				$(_div, { 'class': classes.sScrollHead } )
+					.css( {
+						overflow: 'hidden',
+						position: 'relative',
+						border: 0,
+						width: scrollX ? size(scrollX) : '100%'
+					} )
+					.append(
+						$(_div, { 'class': classes.sScrollHeadInner } )
+							.css( {
+								'box-sizing': 'content-box',
+								width: scroll.sXInner || '100%'
+							} )
+							.append(
+								headerClone
+									.removeAttr('id')
+									.css( 'margin-left', 0 )
+									.append( captionSide === 'top' ? caption : null )
+									.append(
+										table.children('thead')
+									)
+							)
+					)
+			)
+			.append(
+				$(_div, { 'class': classes.sScrollBody } )
+					.css( {
+						overflow: 'auto',
+						height: size( scrollY ),
+						width: size( scrollX )
+					} )
+					.append( table )
+			);
+	
+		if ( footer ) {
+			scroller.append(
+				$(_div, { 'class': classes.sScrollFoot } )
+					.css( {
+						overflow: 'hidden',
+						border: 0,
+						width: scrollX ? size(scrollX) : '100%'
+					} )
+					.append(
+						$(_div, { 'class': classes.sScrollFootInner } )
+							.append(
+								footerClone
+									.removeAttr('id')
+									.css( 'margin-left', 0 )
+									.append( captionSide === 'bottom' ? caption : null )
+									.append(
+										table.children('tfoot')
+									)
+							)
+					)
+			);
+		}
+	
+		var children = scroller.children();
+		var scrollHead = children[0];
+		var scrollBody = children[1];
+		var scrollFoot = footer ? children[2] : null;
+	
+		// When the body is scrolled, then we also want to scroll the headers
+		if ( scrollX ) {
+			$(scrollBody).on( 'scroll.DT', function (e) {
+				var scrollLeft = this.scrollLeft;
+	
+				scrollHead.scrollLeft = scrollLeft;
+	
+				if ( footer ) {
+					scrollFoot.scrollLeft = scrollLeft;
+				}
+			} );
+		}
+	
+		settings.nScrollHead = scrollHead;
+		settings.nScrollBody = scrollBody;
+		settings.nScrollFoot = scrollFoot;
+	
+		// On redraw - align columns
+		settings.aoDrawCallback.push( {
+			"fn": _fnScrollDraw,
+			"sName": "scrolling"
+		} );
+	
+		return scroller[0];
+	}
+	
+	
+	
+	/**
+	 * Update the header, footer and body tables for resizing - i.e. column
+	 * alignment.
+	 *
+	 * Welcome to the most horrible function DataTables. The process that this
+	 * function follows is basically:
+	 *   1. Re-create the table inside the scrolling div
+	 *   2. Take live measurements from the DOM
+	 *   3. Apply the measurements to align the columns
+	 *   4. Clean up
+	 *
+	 *  @param {object} settings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnScrollDraw ( settings )
+	{
+		// Given that this is such a monster function, a lot of variables are use
+		// to try and keep the minimised size as small as possible
+		var
+			scroll         = settings.oScroll,
+			scrollX        = scroll.sX,
+			scrollXInner   = scroll.sXInner,
+			scrollY        = scroll.sY,
+			barWidth       = scroll.iBarWidth,
+			divHeader      = $(settings.nScrollHead),
+			divHeaderStyle = divHeader[0].style,
+			divHeaderInner = divHeader.children('div'),
+			divHeaderInnerStyle = divHeaderInner[0].style,
+			divHeaderTable = divHeaderInner.children('table'),
+			divBodyEl      = settings.nScrollBody,
+			divBody        = $(divBodyEl),
+			divBodyStyle   = divBodyEl.style,
+			divFooter      = $(settings.nScrollFoot),
+			divFooterInner = divFooter.children('div'),
+			divFooterTable = divFooterInner.children('table'),
+			header         = $(settings.nTHead),
+			table          = $(settings.nTable),
+			tableEl        = table[0],
+			tableStyle     = tableEl.style,
+			footer         = settings.nTFoot ? $(settings.nTFoot) : null,
+			browser        = settings.oBrowser,
+			ie67           = browser.bScrollOversize,
+			headerTrgEls, footerTrgEls,
+			headerSrcEls, footerSrcEls,
+			headerCopy, footerCopy,
+			headerWidths=[], footerWidths=[],
+			headerContent=[],
+			idx, correction, sanityWidth,
+			zeroOut = function(nSizer) {
+				var style = nSizer.style;
+				style.paddingTop = "0";
+				style.paddingBottom = "0";
+				style.borderTopWidth = "0";
+				style.borderBottomWidth = "0";
+				style.height = 0;
+			};
+	
+		/*
+		 * 1. Re-create the table inside the scrolling div
+		 */
+	
+		// Remove the old minimised thead and tfoot elements in the inner table
+		table.children('thead, tfoot').remove();
+	
+		// Clone the current header and footer elements and then place it into the inner table
+		headerCopy = header.clone().prependTo( table );
+		headerTrgEls = header.find('tr'); // original header is in its own table
+		headerSrcEls = headerCopy.find('tr');
+		headerCopy.find('th, td').removeAttr('tabindex');
+	
+		if ( footer ) {
+			footerCopy = footer.clone().prependTo( table );
+			footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
+			footerSrcEls = footerCopy.find('tr');
+		}
+	
+	
+		/*
+		 * 2. Take live measurements from the DOM - do not alter the DOM itself!
+		 */
+	
+		// Remove old sizing and apply the calculated column widths
+		// Get the unique column headers in the newly created (cloned) header. We want to apply the
+		// calculated sizes to this header
+		if ( ! scrollX )
+		{
+			divBodyStyle.width = '100%';
+			divHeader[0].style.width = '100%';
+		}
+	
+		$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
+			idx = _fnVisibleToColumnIndex( settings, i );
+			el.style.width = settings.aoColumns[idx].sWidth;
+		} );
+	
+		if ( footer ) {
+			_fnApplyToChildren( function(n) {
+				n.style.width = "";
+			}, footerSrcEls );
+		}
+	
+		// If scroll collapse is enabled, when we put the headers back into the body for sizing, we
+		// will end up forcing the scrollbar to appear, making our measurements wrong for when we
+		// then hide it (end of this function), so add the header height to the body scroller.
+		if ( scroll.bCollapse && scrollY !== "" ) {
+			divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight)+"px";
+		}
+	
+		// Size the table as a whole
+		sanityWidth = table.outerWidth();
+		if ( scrollX === "" ) {
+			// No x scrolling
+			tableStyle.width = "100%";
+	
+			// IE7 will make the width of the table when 100% include the scrollbar
+			// - which is shouldn't. When there is a scrollbar we need to take this
+			// into account.
+			if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
+				divBody.css('overflow-y') == "scroll")
+			) {
+				tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
+			}
+		}
+		else
+		{
+			// x scrolling
+			if ( scrollXInner !== "" ) {
+				// x scroll inner has been given - use it
+				tableStyle.width = _fnStringToCss(scrollXInner);
+			}
+			else if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) {
+				// There is y-scrolling - try to take account of the y scroll bar
+				tableStyle.width = _fnStringToCss( sanityWidth-barWidth );
+				if ( table.outerWidth() > sanityWidth-barWidth ) {
+					// Not possible to take account of it
+					tableStyle.width = _fnStringToCss( sanityWidth );
+				}
+			}
+			else {
+				// When all else fails
+				tableStyle.width = _fnStringToCss( sanityWidth );
+			}
+		}
+	
+		// Recalculate the sanity width - now that we've applied the required width,
+		// before it was a temporary variable. This is required because the column
+		// width calculation is done before this table DOM is created.
+		sanityWidth = table.outerWidth();
+	
+		// Hidden header should have zero height, so remove padding and borders. Then
+		// set the width based on the real headers
+	
+		// Apply all styles in one pass
+		_fnApplyToChildren( zeroOut, headerSrcEls );
+	
+		// Read all widths in next pass
+		_fnApplyToChildren( function(nSizer) {
+			headerContent.push( nSizer.innerHTML );
+			headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
+		}, headerSrcEls );
+	
+		// Apply all widths in final pass
+		_fnApplyToChildren( function(nToSize, i) {
+			nToSize.style.width = headerWidths[i];
+		}, headerTrgEls );
+	
+		$(headerSrcEls).height(0);
+	
+		/* Same again with the footer if we have one */
+		if ( footer )
+		{
+			_fnApplyToChildren( zeroOut, footerSrcEls );
+	
+			_fnApplyToChildren( function(nSizer) {
+				footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
+			}, footerSrcEls );
+	
+			_fnApplyToChildren( function(nToSize, i) {
+				nToSize.style.width = footerWidths[i];
+			}, footerTrgEls );
+	
+			$(footerSrcEls).height(0);
+		}
+	
+	
+		/*
+		 * 3. Apply the measurements
+		 */
+	
+		// "Hide" the header and footer that we used for the sizing. We need to keep
+		// the content of the cell so that the width applied to the header and body
+		// both match, but we want to hide it completely. We want to also fix their
+		// width to what they currently are
+		_fnApplyToChildren( function(nSizer, i) {
+			nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
+			nSizer.style.width = headerWidths[i];
+		}, headerSrcEls );
+	
+		if ( footer )
+		{
+			_fnApplyToChildren( function(nSizer, i) {
+				nSizer.innerHTML = "";
+				nSizer.style.width = footerWidths[i];
+			}, footerSrcEls );
+		}
+	
+		// Sanity check that the table is of a sensible width. If not then we are going to get
+		// misalignment - try to prevent this by not allowing the table to shrink below its min width
+		if ( table.outerWidth() < sanityWidth )
+		{
+			// The min width depends upon if we have a vertical scrollbar visible or not */
+			correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
+				divBody.css('overflow-y') == "scroll")) ?
+					sanityWidth+barWidth :
+					sanityWidth;
+	
+			// IE6/7 are a law unto themselves...
+			if ( ie67 && (divBodyEl.scrollHeight >
+				divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
+			) {
+				tableStyle.width = _fnStringToCss( correction-barWidth );
+			}
+	
+			// And give the user a warning that we've stopped the table getting too small
+			if ( scrollX === "" || scrollXInner !== "" ) {
+				_fnLog( settings, 1, 'Possible column misalignment', 6 );
+			}
+		}
+		else
+		{
+			correction = '100%';
+		}
+	
+		// Apply to the container elements
+		divBodyStyle.width = _fnStringToCss( correction );
+		divHeaderStyle.width = _fnStringToCss( correction );
+	
+		if ( footer ) {
+			settings.nScrollFoot.style.width = _fnStringToCss( correction );
+		}
+	
+	
+		/*
+		 * 4. Clean up
+		 */
+		if ( ! scrollY ) {
+			/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
+			 * the scrollbar height from the visible display, rather than adding it on. We need to
+			 * set the height in order to sort this. Don't want to do it in any other browsers.
+			 */
+			if ( ie67 ) {
+				divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
+			}
+		}
+	
+		if ( scrollY && scroll.bCollapse ) {
+			divBodyStyle.height = _fnStringToCss( scrollY );
+	
+			var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ?
+				barWidth :
+				0;
+	
+			if ( tableEl.offsetHeight < divBodyEl.offsetHeight ) {
+				divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra );
+			}
+		}
+	
+		/* Finally set the width's of the header and footer tables */
+		var iOuterWidth = table.outerWidth();
+		divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
+		divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
+	
+		// Figure out if there are scrollbar present - if so then we need a the header and footer to
+		// provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
+		var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
+		var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
+		divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
+	
+		if ( footer ) {
+			divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
+			divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
+			divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
+		}
+	
+		/* Adjust the position of the header in case we loose the y-scrollbar */
+		divBody.scroll();
+	
+		// If sorting or filtering has occurred, jump the scrolling back to the top
+		// only if we aren't holding the position
+		if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
+			divBodyEl.scrollTop = 0;
+		}
+	}
+	
+	
+	
+	/**
+	 * Apply a given function to the display child nodes of an element array (typically
+	 * TD children of TR rows
+	 *  @param {function} fn Method to apply to the objects
+	 *  @param array {nodes} an1 List of elements to look through for display children
+	 *  @param array {nodes} an2 Another list (identical structure to the first) - optional
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnApplyToChildren( fn, an1, an2 )
+	{
+		var index=0, i=0, iLen=an1.length;
+		var nNode1, nNode2;
+	
+		while ( i < iLen ) {
+			nNode1 = an1[i].firstChild;
+			nNode2 = an2 ? an2[i].firstChild : null;
+	
+			while ( nNode1 ) {
+				if ( nNode1.nodeType === 1 ) {
+					if ( an2 ) {
+						fn( nNode1, nNode2, index );
+					}
+					else {
+						fn( nNode1, index );
+					}
+	
+					index++;
+				}
+	
+				nNode1 = nNode1.nextSibling;
+				nNode2 = an2 ? nNode2.nextSibling : null;
+			}
+	
+			i++;
+		}
+	}
+	
+	
+	
+	var __re_html_remove = /<.*?>/g;
+	
+	
+	/**
+	 * Calculate the width of columns for the table
+	 *  @param {object} oSettings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnCalculateColumnWidths ( oSettings )
+	{
+		var
+			table = oSettings.nTable,
+			columns = oSettings.aoColumns,
+			scroll = oSettings.oScroll,
+			scrollY = scroll.sY,
+			scrollX = scroll.sX,
+			scrollXInner = scroll.sXInner,
+			columnCount = columns.length,
+			visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
+			headerCells = $('th', oSettings.nTHead),
+			tableWidthAttr = table.getAttribute('width'), // from DOM element
+			tableContainer = table.parentNode,
+			userInputs = false,
+			i, column, columnIdx, width, outerWidth;
+	
+		var styleWidth = table.style.width;
+		if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
+			tableWidthAttr = styleWidth;
+		}
+	
+		/* Convert any user input sizes into pixel sizes */
+		for ( i=0 ; i<visibleColumns.length ; i++ ) {
+			column = columns[ visibleColumns[i] ];
+	
+			if ( column.sWidth !== null ) {
+				column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
+	
+				userInputs = true;
+			}
+		}
+	
+		/* If the number of columns in the DOM equals the number that we have to
+		 * process in DataTables, then we can use the offsets that are created by
+		 * the web- browser. No custom sizes can be set in order for this to happen,
+		 * nor scrolling used
+		 */
+		if ( ! userInputs && ! scrollX && ! scrollY &&
+		    columnCount == _fnVisbleColumns( oSettings ) &&
+			columnCount == headerCells.length
+		) {
+			for ( i=0 ; i<columnCount ; i++ ) {
+				columns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() );
+			}
+		}
+		else
+		{
+			// Otherwise construct a single row, worst case, table with the widest
+			// node in the data, assign any user defined widths, then insert it into
+			// the DOM and allow the browser to do all the hard work of calculating
+			// table widths
+			var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
+				.css( 'visibility', 'hidden' )
+				.removeAttr( 'id' );
+	
+			// Clean up the table body
+			tmpTable.find('tbody tr').remove();
+			var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
+	
+			// Remove any assigned widths from the footer (from scrolling)
+			tmpTable.find('tfoot th, tfoot td').css('width', '');
+	
+			// Apply custom sizing to the cloned header
+			headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
+	
+			for ( i=0 ; i<visibleColumns.length ; i++ ) {
+				column = columns[ visibleColumns[i] ];
+	
+				headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
+					_fnStringToCss( column.sWidthOrig ) :
+					'';
+			}
+	
+			// Find the widest cell for each column and put it into the table
+			if ( oSettings.aoData.length ) {
+				for ( i=0 ; i<visibleColumns.length ; i++ ) {
+					columnIdx = visibleColumns[i];
+					column = columns[ columnIdx ];
+	
+					$( _fnGetWidestNode( oSettings, columnIdx ) )
+						.clone( false )
+						.append( column.sContentPadding )
+						.appendTo( tr );
+				}
+			}
+	
+			// Table has been built, attach to the document so we can work with it
+			tmpTable.appendTo( tableContainer );
+	
+			// When scrolling (X or Y) we want to set the width of the table as 
+			// appropriate. However, when not scrolling leave the table width as it
+			// is. This results in slightly different, but I think correct behaviour
+			if ( scrollX && scrollXInner ) {
+				tmpTable.width( scrollXInner );
+			}
+			else if ( scrollX ) {
+				tmpTable.css( 'width', 'auto' );
+	
+				if ( tmpTable.width() < tableContainer.offsetWidth ) {
+					tmpTable.width( tableContainer.offsetWidth );
+				}
+			}
+			else if ( scrollY ) {
+				tmpTable.width( tableContainer.offsetWidth );
+			}
+			else if ( tableWidthAttr ) {
+				tmpTable.width( tableWidthAttr );
+			}
+	
+			// Take into account the y scrollbar
+			_fnScrollingWidthAdjust( oSettings, tmpTable[0] );
+	
+			// Browsers need a bit of a hand when a width is assigned to any columns
+			// when x-scrolling as they tend to collapse the table to the min-width,
+			// even if we sent the column widths. So we need to keep track of what
+			// the table width should be by summing the user given values, and the
+			// automatic values
+			if ( scrollX )
+			{
+				var total = 0;
+	
+				for ( i=0 ; i<visibleColumns.length ; i++ ) {
+					column = columns[ visibleColumns[i] ];
+					outerWidth = $(headerCells[i]).outerWidth();
+	
+					total += column.sWidthOrig === null ?
+						outerWidth :
+						parseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width();
+				}
+	
+				tmpTable.width( _fnStringToCss( total ) );
+				table.style.width = _fnStringToCss( total );
+			}
+	
+			// Get the width of each column in the constructed table
+			for ( i=0 ; i<visibleColumns.length ; i++ ) {
+				column = columns[ visibleColumns[i] ];
+				width = $(headerCells[i]).width();
+	
+				if ( width ) {
+					column.sWidth = _fnStringToCss( width );
+				}
+			}
+	
+			table.style.width = _fnStringToCss( tmpTable.css('width') );
+	
+			// Finished with the table - ditch it
+			tmpTable.remove();
+		}
+	
+		// If there is a width attr, we want to attach an event listener which
+		// allows the table sizing to automatically adjust when the window is
+		// resized. Use the width attr rather than CSS, since we can't know if the
+		// CSS is a relative value or absolute - DOM read is always px.
+		if ( tableWidthAttr ) {
+			table.style.width = _fnStringToCss( tableWidthAttr );
+		}
+	
+		if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
+			var bindResize = function () {
+				$(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
+					_fnAdjustColumnSizing( oSettings );
+				} ) );
+			};
+	
+			// IE6/7 will crash if we bind a resize event handler on page load.
+			// To be removed in 1.11 which drops IE6/7 support
+			if ( oSettings.oBrowser.bScrollOversize ) {
+				setTimeout( bindResize, 1000 );
+			}
+			else {
+				bindResize();
+			}
+	
+			oSettings._reszEvt = true;
+		}
+	}
+	
+	
+	/**
+	 * Throttle the calls to a function. Arguments and context are maintained for
+	 * the throttled function
+	 *  @param {function} fn Function to be called
+	 *  @param {int} [freq=200] call frequency in mS
+	 *  @returns {function} wrapped function
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnThrottle( fn, freq ) {
+		var
+			frequency = freq !== undefined ? freq : 200,
+			last,
+			timer;
+	
+		return function () {
+			var
+				that = this,
+				now  = +new Date(),
+				args = arguments;
+	
+			if ( last && now < last + frequency ) {
+				clearTimeout( timer );
+	
+				timer = setTimeout( function () {
+					last = undefined;
+					fn.apply( that, args );
+				}, frequency );
+			}
+			else {
+				last = now;
+				fn.apply( that, args );
+			}
+		};
+	}
+	
+	
+	/**
+	 * Convert a CSS unit width to pixels (e.g. 2em)
+	 *  @param {string} width width to be converted
+	 *  @param {node} parent parent to get the with for (required for relative widths) - optional
+	 *  @returns {int} width in pixels
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnConvertToWidth ( width, parent )
+	{
+		if ( ! width ) {
+			return 0;
+		}
+	
+		var n = $('<div/>')
+			.css( 'width', _fnStringToCss( width ) )
+			.appendTo( parent || document.body );
+	
+		var val = n[0].offsetWidth;
+		n.remove();
+	
+		return val;
+	}
+	
+	
+	/**
+	 * Adjust a table's width to take account of vertical scroll bar
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {node} n table node
+	 *  @memberof DataTable#oApi
+	 */
+	
+	function _fnScrollingWidthAdjust ( settings, n )
+	{
+		var scroll = settings.oScroll;
+	
+		if ( scroll.sX || scroll.sY ) {
+			// When y-scrolling only, we want to remove the width of the scroll bar
+			// so the table + scroll bar will fit into the area available, otherwise
+			// we fix the table at its current size with no adjustment
+			var correction = ! scroll.sX ? scroll.iBarWidth : 0;
+			n.style.width = _fnStringToCss( $(n).outerWidth() - correction );
+		}
+	}
+	
+	
+	/**
+	 * Get the widest node
+	 *  @param {object} settings dataTables settings object
+	 *  @param {int} colIdx column of interest
+	 *  @returns {node} widest table node
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnGetWidestNode( settings, colIdx )
+	{
+		var idx = _fnGetMaxLenString( settings, colIdx );
+		if ( idx < 0 ) {
+			return null;
+		}
+	
+		var data = settings.aoData[ idx ];
+		return ! data.nTr ? // Might not have been created when deferred rendering
+			$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
+			data.anCells[ colIdx ];
+	}
+	
+	
+	/**
+	 * Get the maximum strlen for each data column
+	 *  @param {object} settings dataTables settings object
+	 *  @param {int} colIdx column of interest
+	 *  @returns {string} max string length for each column
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnGetMaxLenString( settings, colIdx )
+	{
+		var s, max=-1, maxIdx = -1;
+	
+		for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
+			s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
+			s = s.replace( __re_html_remove, '' );
+	
+			if ( s.length > max ) {
+				max = s.length;
+				maxIdx = i;
+			}
+		}
+	
+		return maxIdx;
+	}
+	
+	
+	/**
+	 * Append a CSS unit (only if required) to a string
+	 *  @param {string} value to css-ify
+	 *  @returns {string} value with css unit
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnStringToCss( s )
+	{
+		if ( s === null ) {
+			return '0px';
+		}
+	
+		if ( typeof s == 'number' ) {
+			return s < 0 ?
+				'0px' :
+				s+'px';
+		}
+	
+		// Check it has a unit character already
+		return s.match(/\d$/) ?
+			s+'px' :
+			s;
+	}
+	
+	
+	/**
+	 * Get the width of a scroll bar in this browser being used
+	 *  @returns {int} width in pixels
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnScrollBarWidth ()
+	{
+		// On first run a static variable is set, since this is only needed once.
+		// Subsequent runs will just use the previously calculated value
+		var width = DataTable.__scrollbarWidth;
+	
+		if ( width === undefined ) {
+			var sizer = $('<p/>').css( {
+					position: 'absolute',
+					top: 0,
+					left: 0,
+					width: '100%',
+					height: 150,
+					padding: 0,
+					overflow: 'scroll',
+					visibility: 'hidden'
+				} )
+				.appendTo('body');
+	
+			width = sizer[0].offsetWidth - sizer[0].clientWidth;
+			DataTable.__scrollbarWidth = width;
+	
+			sizer.remove();
+		}
+	
+		return width;
+	}
+	
+	
+	
+	function _fnSortFlatten ( settings )
+	{
+		var
+			i, iLen, k, kLen,
+			aSort = [],
+			aiOrig = [],
+			aoColumns = settings.aoColumns,
+			aDataSort, iCol, sType, srcCol,
+			fixed = settings.aaSortingFixed,
+			fixedObj = $.isPlainObject( fixed ),
+			nestedSort = [],
+			add = function ( a ) {
+				if ( a.length && ! $.isArray( a[0] ) ) {
+					// 1D array
+					nestedSort.push( a );
+				}
+				else {
+					// 2D array
+					nestedSort.push.apply( nestedSort, a );
+				}
+			};
+	
+		// Build the sort array, with pre-fix and post-fix options if they have been
+		// specified
+		if ( $.isArray( fixed ) ) {
+			add( fixed );
+		}
+	
+		if ( fixedObj && fixed.pre ) {
+			add( fixed.pre );
+		}
+	
+		add( settings.aaSorting );
+	
+		if (fixedObj && fixed.post ) {
+			add( fixed.post );
+		}
+	
+		for ( i=0 ; i<nestedSort.length ; i++ )
+		{
+			srcCol = nestedSort[i][0];
+			aDataSort = aoColumns[ srcCol ].aDataSort;
+	
+			for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
+			{
+				iCol = aDataSort[k];
+				sType = aoColumns[ iCol ].sType || 'string';
+	
+				if ( nestedSort[i]._idx === undefined ) {
+					nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
+				}
+	
+				aSort.push( {
+					src:       srcCol,
+					col:       iCol,
+					dir:       nestedSort[i][1],
+					index:     nestedSort[i]._idx,
+					type:      sType,
+					formatter: DataTable.ext.type.order[ sType+"-pre" ]
+				} );
+			}
+		}
+	
+		return aSort;
+	}
+	
+	/**
+	 * Change the order of the table
+	 *  @param {object} oSettings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 *  @todo This really needs split up!
+	 */
+	function _fnSort ( oSettings )
+	{
+		var
+			i, ien, iLen, j, jLen, k, kLen,
+			sDataType, nTh,
+			aiOrig = [],
+			oExtSort = DataTable.ext.type.order,
+			aoData = oSettings.aoData,
+			aoColumns = oSettings.aoColumns,
+			aDataSort, data, iCol, sType, oSort,
+			formatters = 0,
+			sortCol,
+			displayMaster = oSettings.aiDisplayMaster,
+			aSort;
+	
+		// Resolve any column types that are unknown due to addition or invalidation
+		// @todo Can this be moved into a 'data-ready' handler which is called when
+		//   data is going to be used in the table?
+		_fnColumnTypes( oSettings );
+	
+		aSort = _fnSortFlatten( oSettings );
+	
+		for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
+			sortCol = aSort[i];
+	
+			// Track if we can use the fast sort algorithm
+			if ( sortCol.formatter ) {
+				formatters++;
+			}
+	
+			// Load the data needed for the sort, for each cell
+			_fnSortData( oSettings, sortCol.col );
+		}
+	
+		/* No sorting required if server-side or no sorting array */
+		if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
+		{
+			// Create a value - key array of the current row positions such that we can use their
+			// current position during the sort, if values match, in order to perform stable sorting
+			for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
+				aiOrig[ displayMaster[i] ] = i;
+			}
+	
+			/* Do the sort - here we want multi-column sorting based on a given data source (column)
+			 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
+			 * follow on it's own, but this is what we want (example two column sorting):
+			 *  fnLocalSorting = function(a,b){
+			 *    var iTest;
+			 *    iTest = oSort['string-asc']('data11', 'data12');
+			 *      if (iTest !== 0)
+			 *        return iTest;
+			 *    iTest = oSort['numeric-desc']('data21', 'data22');
+			 *    if (iTest !== 0)
+			 *      return iTest;
+			 *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
+			 *  }
+			 * Basically we have a test for each sorting column, if the data in that column is equal,
+			 * test the next column. If all columns match, then we use a numeric sort on the row
+			 * positions in the original data array to provide a stable sort.
+			 *
+			 * Note - I know it seems excessive to have two sorting methods, but the first is around
+			 * 15% faster, so the second is only maintained for backwards compatibility with sorting
+			 * methods which do not have a pre-sort formatting function.
+			 */
+			if ( formatters === aSort.length ) {
+				// All sort types have formatting functions
+				displayMaster.sort( function ( a, b ) {
+					var
+						x, y, k, test, sort,
+						len=aSort.length,
+						dataA = aoData[a]._aSortData,
+						dataB = aoData[b]._aSortData;
+	
+					for ( k=0 ; k<len ; k++ ) {
+						sort = aSort[k];
+	
+						x = dataA[ sort.col ];
+						y = dataB[ sort.col ];
+	
+						test = x<y ? -1 : x>y ? 1 : 0;
+						if ( test !== 0 ) {
+							return sort.dir === 'asc' ? test : -test;
+						}
+					}
+	
+					x = aiOrig[a];
+					y = aiOrig[b];
+					return x<y ? -1 : x>y ? 1 : 0;
+				} );
+			}
+			else {
+				// Depreciated - remove in 1.11 (providing a plug-in option)
+				// Not all sort types have formatting methods, so we have to call their sorting
+				// methods.
+				displayMaster.sort( function ( a, b ) {
+					var
+						x, y, k, l, test, sort, fn,
+						len=aSort.length,
+						dataA = aoData[a]._aSortData,
+						dataB = aoData[b]._aSortData;
+	
+					for ( k=0 ; k<len ; k++ ) {
+						sort = aSort[k];
+	
+						x = dataA[ sort.col ];
+						y = dataB[ sort.col ];
+	
+						fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
+						test = fn( x, y );
+						if ( test !== 0 ) {
+							return test;
+						}
+					}
+	
+					x = aiOrig[a];
+					y = aiOrig[b];
+					return x<y ? -1 : x>y ? 1 : 0;
+				} );
+			}
+		}
+	
+		/* Tell the draw function that we have sorted the data */
+		oSettings.bSorted = true;
+	}
+	
+	
+	function _fnSortAria ( settings )
+	{
+		var label;
+		var nextSort;
+		var columns = settings.aoColumns;
+		var aSort = _fnSortFlatten( settings );
+		var oAria = settings.oLanguage.oAria;
+	
+		// ARIA attributes - need to loop all columns, to update all (removing old
+		// attributes as needed)
+		for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
+		{
+			var col = columns[i];
+			var asSorting = col.asSorting;
+			var sTitle = col.sTitle.replace( /<.*?>/g, "" );
+			var th = col.nTh;
+	
+			// IE7 is throwing an error when setting these properties with jQuery's
+			// attr() and removeAttr() methods...
+			th.removeAttribute('aria-sort');
+	
+			/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
+			if ( col.bSortable ) {
+				if ( aSort.length > 0 && aSort[0].col == i ) {
+					th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
+					nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
+				}
+				else {
+					nextSort = asSorting[0];
+				}
+	
+				label = sTitle + ( nextSort === "asc" ?
+					oAria.sSortAscending :
+					oAria.sSortDescending
+				);
+			}
+			else {
+				label = sTitle;
+			}
+	
+			th.setAttribute('aria-label', label);
+		}
+	}
+	
+	
+	/**
+	 * Function to run on user sort request
+	 *  @param {object} settings dataTables settings object
+	 *  @param {node} attachTo node to attach the handler to
+	 *  @param {int} colIdx column sorting index
+	 *  @param {boolean} [append=false] Append the requested sort to the existing
+	 *    sort if true (i.e. multi-column sort)
+	 *  @param {function} [callback] callback function
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnSortListener ( settings, colIdx, append, callback )
+	{
+		var col = settings.aoColumns[ colIdx ];
+		var sorting = settings.aaSorting;
+		var asSorting = col.asSorting;
+		var nextSortIdx;
+		var next = function ( a, overflow ) {
+			var idx = a._idx;
+			if ( idx === undefined ) {
+				idx = $.inArray( a[1], asSorting );
+			}
+	
+			return idx+1 < asSorting.length ?
+				idx+1 :
+				overflow ?
+					null :
+					0;
+		};
+	
+		// Convert to 2D array if needed
+		if ( typeof sorting[0] === 'number' ) {
+			sorting = settings.aaSorting = [ sorting ];
+		}
+	
+		// If appending the sort then we are multi-column sorting
+		if ( append && settings.oFeatures.bSortMulti ) {
+			// Are we already doing some kind of sort on this column?
+			var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
+	
+			if ( sortIdx !== -1 ) {
+				// Yes, modify the sort
+				nextSortIdx = next( sorting[sortIdx], true );
+	
+				if ( nextSortIdx === null && sorting.length === 1 ) {
+					nextSortIdx = 0; // can't remove sorting completely
+				}
+	
+				if ( nextSortIdx === null ) {
+					sorting.splice( sortIdx, 1 );
+				}
+				else {
+					sorting[sortIdx][1] = asSorting[ nextSortIdx ];
+					sorting[sortIdx]._idx = nextSortIdx;
+				}
+			}
+			else {
+				// No sort on this column yet
+				sorting.push( [ colIdx, asSorting[0], 0 ] );
+				sorting[sorting.length-1]._idx = 0;
+			}
+		}
+		else if ( sorting.length && sorting[0][0] == colIdx ) {
+			// Single column - already sorting on this column, modify the sort
+			nextSortIdx = next( sorting[0] );
+	
+			sorting.length = 1;
+			sorting[0][1] = asSorting[ nextSortIdx ];
+			sorting[0]._idx = nextSortIdx;
+		}
+		else {
+			// Single column - sort only on this column
+			sorting.length = 0;
+			sorting.push( [ colIdx, asSorting[0] ] );
+			sorting[0]._idx = 0;
+		}
+	
+		// Run the sort by calling a full redraw
+		_fnReDraw( settings );
+	
+		// callback used for async user interaction
+		if ( typeof callback == 'function' ) {
+			callback( settings );
+		}
+	}
+	
+	
+	/**
+	 * Attach a sort handler (click) to a node
+	 *  @param {object} settings dataTables settings object
+	 *  @param {node} attachTo node to attach the handler to
+	 *  @param {int} colIdx column sorting index
+	 *  @param {function} [callback] callback function
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
+	{
+		var col = settings.aoColumns[ colIdx ];
+	
+		_fnBindAction( attachTo, {}, function (e) {
+			/* If the column is not sortable - don't to anything */
+			if ( col.bSortable === false ) {
+				return;
+			}
+	
+			// If processing is enabled use a timeout to allow the processing
+			// display to be shown - otherwise to it synchronously
+			if ( settings.oFeatures.bProcessing ) {
+				_fnProcessingDisplay( settings, true );
+	
+				setTimeout( function() {
+					_fnSortListener( settings, colIdx, e.shiftKey, callback );
+	
+					// In server-side processing, the draw callback will remove the
+					// processing display
+					if ( _fnDataSource( settings ) !== 'ssp' ) {
+						_fnProcessingDisplay( settings, false );
+					}
+				}, 0 );
+			}
+			else {
+				_fnSortListener( settings, colIdx, e.shiftKey, callback );
+			}
+		} );
+	}
+	
+	
+	/**
+	 * Set the sorting classes on table's body, Note: it is safe to call this function
+	 * when bSort and bSortClasses are false
+	 *  @param {object} oSettings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnSortingClasses( settings )
+	{
+		var oldSort = settings.aLastSort;
+		var sortClass = settings.oClasses.sSortColumn;
+		var sort = _fnSortFlatten( settings );
+		var features = settings.oFeatures;
+		var i, ien, colIdx;
+	
+		if ( features.bSort && features.bSortClasses ) {
+			// Remove old sorting classes
+			for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
+				colIdx = oldSort[i].src;
+	
+				// Remove column sorting
+				$( _pluck( settings.aoData, 'anCells', colIdx ) )
+					.removeClass( sortClass + (i<2 ? i+1 : 3) );
+			}
+	
+			// Add new column sorting
+			for ( i=0, ien=sort.length ; i<ien ; i++ ) {
+				colIdx = sort[i].src;
+	
+				$( _pluck( settings.aoData, 'anCells', colIdx ) )
+					.addClass( sortClass + (i<2 ? i+1 : 3) );
+			}
+		}
+	
+		settings.aLastSort = sort;
+	}
+	
+	
+	// Get the data to sort a column, be it from cache, fresh (populating the
+	// cache), or from a sort formatter
+	function _fnSortData( settings, idx )
+	{
+		// Custom sorting function - provided by the sort data type
+		var column = settings.aoColumns[ idx ];
+		var customSort = DataTable.ext.order[ column.sSortDataType ];
+		var customData;
+	
+		if ( customSort ) {
+			customData = customSort.call( settings.oInstance, settings, idx,
+				_fnColumnIndexToVisible( settings, idx )
+			);
+		}
+	
+		// Use / populate cache
+		var row, cellData;
+		var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
+	
+		for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
+			row = settings.aoData[i];
+	
+			if ( ! row._aSortData ) {
+				row._aSortData = [];
+			}
+	
+			if ( ! row._aSortData[idx] || customSort ) {
+				cellData = customSort ?
+					customData[i] : // If there was a custom sort function, use data from there
+					_fnGetCellData( settings, i, idx, 'sort' );
+	
+				row._aSortData[ idx ] = formatter ?
+					formatter( cellData ) :
+					cellData;
+			}
+		}
+	}
+	
+	
+	
+	/**
+	 * Save the state of a table
+	 *  @param {object} oSettings dataTables settings object
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnSaveState ( settings )
+	{
+		if ( !settings.oFeatures.bStateSave || settings.bDestroying )
+		{
+			return;
+		}
+	
+		/* Store the interesting variables */
+		var state = {
+			time:    +new Date(),
+			start:   settings._iDisplayStart,
+			length:  settings._iDisplayLength,
+			order:   $.extend( true, [], settings.aaSorting ),
+			search:  _fnSearchToCamel( settings.oPreviousSearch ),
+			columns: $.map( settings.aoColumns, function ( col, i ) {
+				return {
+					visible: col.bVisible,
+					search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
+				};
+			} )
+		};
+	
+		_fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
+	
+		settings.oSavedState = state;
+		settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
+	}
+	
+	
+	/**
+	 * Attempt to load a saved table state
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {object} oInit DataTables init object so we can override settings
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnLoadState ( settings, oInit )
+	{
+		var i, ien;
+		var columns = settings.aoColumns;
+	
+		if ( ! settings.oFeatures.bStateSave ) {
+			return;
+		}
+	
+		var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
+		if ( ! state || ! state.time ) {
+			return;
+		}
+	
+		/* Allow custom and plug-in manipulation functions to alter the saved data set and
+		 * cancelling of loading by returning false
+		 */
+		var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
+		if ( $.inArray( false, abStateLoad ) !== -1 ) {
+			return;
+		}
+	
+		/* Reject old data */
+		var duration = settings.iStateDuration;
+		if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
+			return;
+		}
+	
+		// Number of columns have changed - all bets are off, no restore of settings
+		if ( columns.length !== state.columns.length ) {
+			return;
+		}
+	
+		// Store the saved state so it might be accessed at any time
+		settings.oLoadedState = $.extend( true, {}, state );
+	
+		// Restore key features - todo - for 1.11 this needs to be done by
+		// subscribed events
+		if ( state.start !== undefined ) {
+			settings._iDisplayStart    = state.start;
+			settings.iInitDisplayStart = state.start;
+		}
+		if ( state.length !== undefined ) {
+			settings._iDisplayLength   = state.length;
+		}
+	
+		// Order
+		if ( state.order !== undefined ) {
+			settings.aaSorting = [];
+			$.each( state.order, function ( i, col ) {
+				settings.aaSorting.push( col[0] >= columns.length ?
+					[ 0, col[1] ] :
+					col
+				);
+			} );
+		}
+	
+		// Search
+		if ( state.search !== undefined ) {
+			$.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
+		}
+	
+		// Columns
+		for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
+			var col = state.columns[i];
+	
+			// Visibility
+			if ( col.visible !== undefined ) {
+				columns[i].bVisible = col.visible;
+			}
+	
+			// Search
+			if ( col.search !== undefined ) {
+				$.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
+			}
+		}
+	
+		_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
+	}
+	
+	
+	/**
+	 * Return the settings object for a particular table
+	 *  @param {node} table table we are using as a dataTable
+	 *  @returns {object} Settings object - or null if not found
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnSettingsFromNode ( table )
+	{
+		var settings = DataTable.settings;
+		var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
+	
+		return idx !== -1 ?
+			settings[ idx ] :
+			null;
+	}
+	
+	
+	/**
+	 * Log an error message
+	 *  @param {object} settings dataTables settings object
+	 *  @param {int} level log error messages, or display them to the user
+	 *  @param {string} msg error message
+	 *  @param {int} tn Technical note id to get more information about the error.
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnLog( settings, level, msg, tn )
+	{
+		msg = 'DataTables warning: '+
+			(settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg;
+	
+		if ( tn ) {
+			msg += '. For more information about this error, please see '+
+			'http://datatables.net/tn/'+tn;
+		}
+	
+		if ( ! level  ) {
+			// Backwards compatibility pre 1.10
+			var ext = DataTable.ext;
+			var type = ext.sErrMode || ext.errMode;
+	
+			_fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
+	
+			if ( type == 'alert' ) {
+				alert( msg );
+			}
+			else if ( type == 'throw' ) {
+				throw new Error(msg);
+			}
+			else if ( typeof type == 'function' ) {
+				type( settings, tn, msg );
+			}
+		}
+		else if ( window.console && console.log ) {
+			console.log( msg );
+		}
+	}
+	
+	
+	/**
+	 * See if a property is defined on one object, if so assign it to the other object
+	 *  @param {object} ret target object
+	 *  @param {object} src source object
+	 *  @param {string} name property
+	 *  @param {string} [mappedName] name to map too - optional, name used if not given
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnMap( ret, src, name, mappedName )
+	{
+		if ( $.isArray( name ) ) {
+			$.each( name, function (i, val) {
+				if ( $.isArray( val ) ) {
+					_fnMap( ret, src, val[0], val[1] );
+				}
+				else {
+					_fnMap( ret, src, val );
+				}
+			} );
+	
+			return;
+		}
+	
+		if ( mappedName === undefined ) {
+			mappedName = name;
+		}
+	
+		if ( src[name] !== undefined ) {
+			ret[mappedName] = src[name];
+		}
+	}
+	
+	
+	/**
+	 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
+	 * shallow copy arrays. The reason we need to do this, is that we don't want to
+	 * deep copy array init values (such as aaSorting) since the dev wouldn't be
+	 * able to override them, but we do want to deep copy arrays.
+	 *  @param {object} out Object to extend
+	 *  @param {object} extender Object from which the properties will be applied to
+	 *      out
+	 *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
+	 *      independent copy with the exception of the `data` or `aaData` parameters
+	 *      if they are present. This is so you can pass in a collection to
+	 *      DataTables and have that used as your data source without breaking the
+	 *      references
+	 *  @returns {object} out Reference, just for convenience - out === the return.
+	 *  @memberof DataTable#oApi
+	 *  @todo This doesn't take account of arrays inside the deep copied objects.
+	 */
+	function _fnExtend( out, extender, breakRefs )
+	{
+		var val;
+	
+		for ( var prop in extender ) {
+			if ( extender.hasOwnProperty(prop) ) {
+				val = extender[prop];
+	
+				if ( $.isPlainObject( val ) ) {
+					if ( ! $.isPlainObject( out[prop] ) ) {
+						out[prop] = {};
+					}
+					$.extend( true, out[prop], val );
+				}
+				else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
+					out[prop] = val.slice();
+				}
+				else {
+					out[prop] = val;
+				}
+			}
+		}
+	
+		return out;
+	}
+	
+	
+	/**
+	 * Bind an event handers to allow a click or return key to activate the callback.
+	 * This is good for accessibility since a return on the keyboard will have the
+	 * same effect as a click, if the element has focus.
+	 *  @param {element} n Element to bind the action to
+	 *  @param {object} oData Data object to pass to the triggered function
+	 *  @param {function} fn Callback function for when the event is triggered
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnBindAction( n, oData, fn )
+	{
+		$(n)
+			.bind( 'click.DT', oData, function (e) {
+					n.blur(); // Remove focus outline for mouse users
+					fn(e);
+				} )
+			.bind( 'keypress.DT', oData, function (e){
+					if ( e.which === 13 ) {
+						e.preventDefault();
+						fn(e);
+					}
+				} )
+			.bind( 'selectstart.DT', function () {
+					/* Take the brutal approach to cancelling text selection */
+					return false;
+				} );
+	}
+	
+	
+	/**
+	 * Register a callback function. Easily allows a callback function to be added to
+	 * an array store of callback functions that can then all be called together.
+	 *  @param {object} oSettings dataTables settings object
+	 *  @param {string} sStore Name of the array storage for the callbacks in oSettings
+	 *  @param {function} fn Function to be called back
+	 *  @param {string} sName Identifying name for the callback (i.e. a label)
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnCallbackReg( oSettings, sStore, fn, sName )
+	{
+		if ( fn )
+		{
+			oSettings[sStore].push( {
+				"fn": fn,
+				"sName": sName
+			} );
+		}
+	}
+	
+	
+	/**
+	 * Fire callback functions and trigger events. Note that the loop over the
+	 * callback array store is done backwards! Further note that you do not want to
+	 * fire off triggers in time sensitive applications (for example cell creation)
+	 * as its slow.
+	 *  @param {object} settings dataTables settings object
+	 *  @param {string} callbackArr Name of the array storage for the callbacks in
+	 *      oSettings
+	 *  @param {string} eventName Name of the jQuery custom event to trigger. If
+	 *      null no trigger is fired
+	 *  @param {array} args Array of arguments to pass to the callback function /
+	 *      trigger
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnCallbackFire( settings, callbackArr, eventName, args )
+	{
+		var ret = [];
+	
+		if ( callbackArr ) {
+			ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
+				return val.fn.apply( settings.oInstance, args );
+			} );
+		}
+	
+		if ( eventName !== null ) {
+			var e = $.Event( eventName+'.dt' );
+	
+			$(settings.nTable).trigger( e, args );
+	
+			ret.push( e.result );
+		}
+	
+		return ret;
+	}
+	
+	
+	function _fnLengthOverflow ( settings )
+	{
+		var
+			start = settings._iDisplayStart,
+			end = settings.fnDisplayEnd(),
+			len = settings._iDisplayLength;
+	
+		/* If we have space to show extra rows (backing up from the end point - then do so */
+		if ( start >= end )
+		{
+			start = end - len;
+		}
+	
+		// Keep the start record on the current page
+		start -= (start % len);
+	
+		if ( len === -1 || start < 0 )
+		{
+			start = 0;
+		}
+	
+		settings._iDisplayStart = start;
+	}
+	
+	
+	function _fnRenderer( settings, type )
+	{
+		var renderer = settings.renderer;
+		var host = DataTable.ext.renderer[type];
+	
+		if ( $.isPlainObject( renderer ) && renderer[type] ) {
+			// Specific renderer for this type. If available use it, otherwise use
+			// the default.
+			return host[renderer[type]] || host._;
+		}
+		else if ( typeof renderer === 'string' ) {
+			// Common renderer - if there is one available for this type use it,
+			// otherwise use the default
+			return host[renderer] || host._;
+		}
+	
+		// Use the default
+		return host._;
+	}
+	
+	
+	/**
+	 * Detect the data source being used for the table. Used to simplify the code
+	 * a little (ajax) and to make it compress a little smaller.
+	 *
+	 *  @param {object} settings dataTables settings object
+	 *  @returns {string} Data source
+	 *  @memberof DataTable#oApi
+	 */
+	function _fnDataSource ( settings )
+	{
+		if ( settings.oFeatures.bServerSide ) {
+			return 'ssp';
+		}
+		else if ( settings.ajax || settings.sAjaxSource ) {
+			return 'ajax';
+		}
+		return 'dom';
+	}
+	
+
+	DataTable = function( options )
+	{
+		/**
+		 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
+		 * return the resulting jQuery object.
+		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
+		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
+		 *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
+		 *    criterion ("applied") or all TR elements (i.e. no filter).
+		 *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
+		 *    Can be either 'current', whereby the current sorting of the table is used, or
+		 *    'original' whereby the original order the data was read into the table is used.
+		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
+		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be
+		 *    'current' and filter is 'applied', regardless of what they might be given as.
+		 *  @returns {object} jQuery object, filtered by the given selector.
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *
+		 *      // Highlight every second row
+		 *      oTable.$('tr:odd').css('backgroundColor', 'blue');
+		 *    } );
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *
+		 *      // Filter to rows with 'Webkit' in them, add a background colour and then
+		 *      // remove the filter, thus highlighting the 'Webkit' rows only.
+		 *      oTable.fnFilter('Webkit');
+		 *      oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
+		 *      oTable.fnFilter('');
+		 *    } );
+		 */
+		this.$ = function ( sSelector, oOpts )
+		{
+			return this.api(true).$( sSelector, oOpts );
+		};
+		
+		
+		/**
+		 * Almost identical to $ in operation, but in this case returns the data for the matched
+		 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
+		 * rather than any descendants, so the data can be obtained for the row/cell. If matching
+		 * rows are found, the data returned is the original data array/object that was used to
+		 * create the row (or a generated array if from a DOM source).
+		 *
+		 * This method is often useful in-combination with $ where both functions are given the
+		 * same parameters and the array indexes will match identically.
+		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
+		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
+		 *  @param {string} [oOpts.filter=none] Select elements that meet the current filter
+		 *    criterion ("applied") or all elements (i.e. no filter).
+		 *  @param {string} [oOpts.order=current] Order of the data in the processed array.
+		 *    Can be either 'current', whereby the current sorting of the table is used, or
+		 *    'original' whereby the original order the data was read into the table is used.
+		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
+		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be
+		 *    'current' and filter is 'applied', regardless of what they might be given as.
+		 *  @returns {array} Data for the matched elements. If any elements, as a result of the
+		 *    selector, were not TR, TD or TH elements in the DataTable, they will have a null
+		 *    entry in the array.
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *
+		 *      // Get the data from the first row in the table
+		 *      var data = oTable._('tr:first');
+		 *
+		 *      // Do something useful with the data
+		 *      alert( "First cell is: "+data[0] );
+		 *    } );
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *
+		 *      // Filter to 'Webkit' and get all data for
+		 *      oTable.fnFilter('Webkit');
+		 *      var data = oTable._('tr', {"search": "applied"});
+		 *
+		 *      // Do something with the data
+		 *      alert( data.length+" rows matched the search" );
+		 *    } );
+		 */
+		this._ = function ( sSelector, oOpts )
+		{
+			return this.api(true).rows( sSelector, oOpts ).data();
+		};
+		
+		
+		/**
+		 * Create a DataTables Api instance, with the currently selected tables for
+		 * the Api's context.
+		 * @param {boolean} [traditional=false] Set the API instance's context to be
+		 *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was
+		 *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),
+		 *   or if all tables captured in the jQuery object should be used.
+		 * @return {DataTables.Api}
+		 */
+		this.api = function ( traditional )
+		{
+			return traditional ?
+				new _Api(
+					_fnSettingsFromNode( this[ _ext.iApiIndex ] )
+				) :
+				new _Api( this );
+		};
+		
+		
+		/**
+		 * Add a single new row or multiple rows of data to the table. Please note
+		 * that this is suitable for client-side processing only - if you are using
+		 * server-side processing (i.e. "bServerSide": true), then to add data, you
+		 * must add it to the data source, i.e. the server-side, through an Ajax call.
+		 *  @param {array|object} data The data to be added to the table. This can be:
+		 *    <ul>
+		 *      <li>1D array of data - add a single row with the data provided</li>
+		 *      <li>2D array of arrays - add multiple rows in a single call</li>
+		 *      <li>object - data object when using <i>mData</i></li>
+		 *      <li>array of objects - multiple data objects when using <i>mData</i></li>
+		 *    </ul>
+		 *  @param {bool} [redraw=true] redraw the table or not
+		 *  @returns {array} An array of integers, representing the list of indexes in
+		 *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
+		 *    the table.
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    // Global var for counter
+		 *    var giCount = 2;
+		 *
+		 *    $(document).ready(function() {
+		 *      $('#example').dataTable();
+		 *    } );
+		 *
+		 *    function fnClickAddRow() {
+		 *      $('#example').dataTable().fnAddData( [
+		 *        giCount+".1",
+		 *        giCount+".2",
+		 *        giCount+".3",
+		 *        giCount+".4" ]
+		 *      );
+		 *
+		 *      giCount++;
+		 *    }
+		 */
+		this.fnAddData = function( data, redraw )
+		{
+			var api = this.api( true );
+		
+			/* Check if we want to add multiple rows or not */
+			var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
+				api.rows.add( data ) :
+				api.row.add( data );
+		
+			if ( redraw === undefined || redraw ) {
+				api.draw();
+			}
+		
+			return rows.flatten().toArray();
+		};
+		
+		
+		/**
+		 * This function will make DataTables recalculate the column sizes, based on the data
+		 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
+		 * through the sWidth parameter). This can be useful when the width of the table's
+		 * parent element changes (for example a window resize).
+		 *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable( {
+		 *        "sScrollY": "200px",
+		 *        "bPaginate": false
+		 *      } );
+		 *
+		 *      $(window).bind('resize', function () {
+		 *        oTable.fnAdjustColumnSizing();
+		 *      } );
+		 *    } );
+		 */
+		this.fnAdjustColumnSizing = function ( bRedraw )
+		{
+			var api = this.api( true ).columns.adjust();
+			var settings = api.settings()[0];
+			var scroll = settings.oScroll;
+		
+			if ( bRedraw === undefined || bRedraw ) {
+				api.draw( false );
+			}
+			else if ( scroll.sX !== "" || scroll.sY !== "" ) {
+				/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
+				_fnScrollDraw( settings );
+			}
+		};
+		
+		
+		/**
+		 * Quickly and simply clear a table
+		 *  @param {bool} [bRedraw=true] redraw the table or not
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *
+		 *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
+		 *      oTable.fnClearTable();
+		 *    } );
+		 */
+		this.fnClearTable = function( bRedraw )
+		{
+			var api = this.api( true ).clear();
+		
+			if ( bRedraw === undefined || bRedraw ) {
+				api.draw();
+			}
+		};
+		
+		
+		/**
+		 * The exact opposite of 'opening' a row, this function will close any rows which
+		 * are currently 'open'.
+		 *  @param {node} nTr the table row to 'close'
+		 *  @returns {int} 0 on success, or 1 if failed (can't find the row)
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable;
+		 *
+		 *      // 'open' an information row when a row is clicked on
+		 *      $('#example tbody tr').click( function () {
+		 *        if ( oTable.fnIsOpen(this) ) {
+		 *          oTable.fnClose( this );
+		 *        } else {
+		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
+		 *        }
+		 *      } );
+		 *
+		 *      oTable = $('#example').dataTable();
+		 *    } );
+		 */
+		this.fnClose = function( nTr )
+		{
+			this.api( true ).row( nTr ).child.hide();
+		};
+		
+		
+		/**
+		 * Remove a row for the table
+		 *  @param {mixed} target The index of the row from aoData to be deleted, or
+		 *    the TR element you want to delete
+		 *  @param {function|null} [callBack] Callback function
+		 *  @param {bool} [redraw=true] Redraw the table or not
+		 *  @returns {array} The row that was deleted
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *
+		 *      // Immediately remove the first row
+		 *      oTable.fnDeleteRow( 0 );
+		 *    } );
+		 */
+		this.fnDeleteRow = function( target, callback, redraw )
+		{
+			var api = this.api( true );
+			var rows = api.rows( target );
+			var settings = rows.settings()[0];
+			var data = settings.aoData[ rows[0][0] ];
+		
+			rows.remove();
+		
+			if ( callback ) {
+				callback.call( this, settings, data );
+			}
+		
+			if ( redraw === undefined || redraw ) {
+				api.draw();
+			}
+		
+			return data;
+		};
+		
+		
+		/**
+		 * Restore the table to it's original state in the DOM by removing all of DataTables
+		 * enhancements, alterations to the DOM structure of the table and event listeners.
+		 *  @param {boolean} [remove=false] Completely remove the table from the DOM
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      // This example is fairly pointless in reality, but shows how fnDestroy can be used
+		 *      var oTable = $('#example').dataTable();
+		 *      oTable.fnDestroy();
+		 *    } );
+		 */
+		this.fnDestroy = function ( remove )
+		{
+			this.api( true ).destroy( remove );
+		};
+		
+		
+		/**
+		 * Redraw the table
+		 *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *
+		 *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
+		 *      oTable.fnDraw();
+		 *    } );
+		 */
+		this.fnDraw = function( complete )
+		{
+			// Note that this isn't an exact match to the old call to _fnDraw - it takes
+			// into account the new data, but can hold position.
+			this.api( true ).draw( complete );
+		};
+		
+		
+		/**
+		 * Filter the input based on data
+		 *  @param {string} sInput String to filter the table on
+		 *  @param {int|null} [iColumn] Column to limit filtering to
+		 *  @param {bool} [bRegex=false] Treat as regular expression or not
+		 *  @param {bool} [bSmart=true] Perform smart filtering or not
+		 *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
+		 *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *
+		 *      // Sometime later - filter...
+		 *      oTable.fnFilter( 'test string' );
+		 *    } );
+		 */
+		this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
+		{
+			var api = this.api( true );
+		
+			if ( iColumn === null || iColumn === undefined ) {
+				api.search( sInput, bRegex, bSmart, bCaseInsensitive );
+			}
+			else {
+				api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
+			}
+		
+			api.draw();
+		};
+		
+		
+		/**
+		 * Get the data for the whole table, an individual row or an individual cell based on the
+		 * provided parameters.
+		 *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
+		 *    a TR node then the data source for the whole row will be returned. If given as a
+		 *    TD/TH cell node then iCol will be automatically calculated and the data for the
+		 *    cell returned. If given as an integer, then this is treated as the aoData internal
+		 *    data index for the row (see fnGetPosition) and the data for that row used.
+		 *  @param {int} [col] Optional column index that you want the data of.
+		 *  @returns {array|object|string} If mRow is undefined, then the data for all rows is
+		 *    returned. If mRow is defined, just data for that row, and is iCol is
+		 *    defined, only data for the designated cell is returned.
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    // Row data
+		 *    $(document).ready(function() {
+		 *      oTable = $('#example').dataTable();
+		 *
+		 *      oTable.$('tr').click( function () {
+		 *        var data = oTable.fnGetData( this );
+		 *        // ... do something with the array / object of data for the row
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Individual cell data
+		 *    $(document).ready(function() {
+		 *      oTable = $('#example').dataTable();
+		 *
+		 *      oTable.$('td').click( function () {
+		 *        var sData = oTable.fnGetData( this );
+		 *        alert( 'The cell clicked on had the value of '+sData );
+		 *      } );
+		 *    } );
+		 */
+		this.fnGetData = function( src, col )
+		{
+			var api = this.api( true );
+		
+			if ( src !== undefined ) {
+				var type = src.nodeName ? src.nodeName.toLowerCase() : '';
+		
+				return col !== undefined || type == 'td' || type == 'th' ?
+					api.cell( src, col ).data() :
+					api.row( src ).data() || null;
+			}
+		
+			return api.data().toArray();
+		};
+		
+		
+		/**
+		 * Get an array of the TR nodes that are used in the table's body. Note that you will
+		 * typically want to use the '$' API method in preference to this as it is more
+		 * flexible.
+		 *  @param {int} [iRow] Optional row index for the TR element you want
+		 *  @returns {array|node} If iRow is undefined, returns an array of all TR elements
+		 *    in the table's body, or iRow is defined, just the TR element requested.
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *
+		 *      // Get the nodes from the table
+		 *      var nNodes = oTable.fnGetNodes( );
+		 *    } );
+		 */
+		this.fnGetNodes = function( iRow )
+		{
+			var api = this.api( true );
+		
+			return iRow !== undefined ?
+				api.row( iRow ).node() :
+				api.rows().nodes().flatten().toArray();
+		};
+		
+		
+		/**
+		 * Get the array indexes of a particular cell from it's DOM element
+		 * and column index including hidden columns
+		 *  @param {node} node this can either be a TR, TD or TH in the table's body
+		 *  @returns {int} If nNode is given as a TR, then a single index is returned, or
+		 *    if given as a cell, an array of [row index, column index (visible),
+		 *    column index (all)] is given.
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      $('#example tbody td').click( function () {
+		 *        // Get the position of the current data from the node
+		 *        var aPos = oTable.fnGetPosition( this );
+		 *
+		 *        // Get the data array for this row
+		 *        var aData = oTable.fnGetData( aPos[0] );
+		 *
+		 *        // Update the data array and return the value
+		 *        aData[ aPos[1] ] = 'clicked';
+		 *        this.innerHTML = 'clicked';
+		 *      } );
+		 *
+		 *      // Init DataTables
+		 *      oTable = $('#example').dataTable();
+		 *    } );
+		 */
+		this.fnGetPosition = function( node )
+		{
+			var api = this.api( true );
+			var nodeName = node.nodeName.toUpperCase();
+		
+			if ( nodeName == 'TR' ) {
+				return api.row( node ).index();
+			}
+			else if ( nodeName == 'TD' || nodeName == 'TH' ) {
+				var cell = api.cell( node ).index();
+		
+				return [
+					cell.row,
+					cell.columnVisible,
+					cell.column
+				];
+			}
+			return null;
+		};
+		
+		
+		/**
+		 * Check to see if a row is 'open' or not.
+		 *  @param {node} nTr the table row to check
+		 *  @returns {boolean} true if the row is currently open, false otherwise
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable;
+		 *
+		 *      // 'open' an information row when a row is clicked on
+		 *      $('#example tbody tr').click( function () {
+		 *        if ( oTable.fnIsOpen(this) ) {
+		 *          oTable.fnClose( this );
+		 *        } else {
+		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
+		 *        }
+		 *      } );
+		 *
+		 *      oTable = $('#example').dataTable();
+		 *    } );
+		 */
+		this.fnIsOpen = function( nTr )
+		{
+			return this.api( true ).row( nTr ).child.isShown();
+		};
+		
+		
+		/**
+		 * This function will place a new row directly after a row which is currently
+		 * on display on the page, with the HTML contents that is passed into the
+		 * function. This can be used, for example, to ask for confirmation that a
+		 * particular record should be deleted.
+		 *  @param {node} nTr The table row to 'open'
+		 *  @param {string|node|jQuery} mHtml The HTML to put into the row
+		 *  @param {string} sClass Class to give the new TD cell
+		 *  @returns {node} The row opened. Note that if the table row passed in as the
+		 *    first parameter, is not found in the table, this method will silently
+		 *    return.
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable;
+		 *
+		 *      // 'open' an information row when a row is clicked on
+		 *      $('#example tbody tr').click( function () {
+		 *        if ( oTable.fnIsOpen(this) ) {
+		 *          oTable.fnClose( this );
+		 *        } else {
+		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
+		 *        }
+		 *      } );
+		 *
+		 *      oTable = $('#example').dataTable();
+		 *    } );
+		 */
+		this.fnOpen = function( nTr, mHtml, sClass )
+		{
+			return this.api( true )
+				.row( nTr )
+				.child( mHtml, sClass )
+				.show()
+				.child()[0];
+		};
+		
+		
+		/**
+		 * Change the pagination - provides the internal logic for pagination in a simple API
+		 * function. With this function you can have a DataTables table go to the next,
+		 * previous, first or last pages.
+		 *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
+		 *    or page number to jump to (integer), note that page 0 is the first page.
+		 *  @param {bool} [bRedraw=true] Redraw the table or not
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *      oTable.fnPageChange( 'next' );
+		 *    } );
+		 */
+		this.fnPageChange = function ( mAction, bRedraw )
+		{
+			var api = this.api( true ).page( mAction );
+		
+			if ( bRedraw === undefined || bRedraw ) {
+				api.draw(false);
+			}
+		};
+		
+		
+		/**
+		 * Show a particular column
+		 *  @param {int} iCol The column whose display should be changed
+		 *  @param {bool} bShow Show (true) or hide (false) the column
+		 *  @param {bool} [bRedraw=true] Redraw the table or not
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *
+		 *      // Hide the second column after initialisation
+		 *      oTable.fnSetColumnVis( 1, false );
+		 *    } );
+		 */
+		this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
+		{
+			var api = this.api( true ).column( iCol ).visible( bShow );
+		
+			if ( bRedraw === undefined || bRedraw ) {
+				api.columns.adjust().draw();
+			}
+		};
+		
+		
+		/**
+		 * Get the settings for a particular table for external manipulation
+		 *  @returns {object} DataTables settings object. See
+		 *    {@link DataTable.models.oSettings}
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *      var oSettings = oTable.fnSettings();
+		 *
+		 *      // Show an example parameter from the settings
+		 *      alert( oSettings._iDisplayStart );
+		 *    } );
+		 */
+		this.fnSettings = function()
+		{
+			return _fnSettingsFromNode( this[_ext.iApiIndex] );
+		};
+		
+		
+		/**
+		 * Sort the table by a particular column
+		 *  @param {int} iCol the data index to sort on. Note that this will not match the
+		 *    'display index' if you have hidden data entries
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *
+		 *      // Sort immediately with columns 0 and 1
+		 *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
+		 *    } );
+		 */
+		this.fnSort = function( aaSort )
+		{
+			this.api( true ).order( aaSort ).draw();
+		};
+		
+		
+		/**
+		 * Attach a sort listener to an element for a given column
+		 *  @param {node} nNode the element to attach the sort listener to
+		 *  @param {int} iColumn the column that a click on this node will sort on
+		 *  @param {function} [fnCallback] callback function when sort is run
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *
+		 *      // Sort on column 1, when 'sorter' is clicked on
+		 *      oTable.fnSortListener( document.getElementById('sorter'), 1 );
+		 *    } );
+		 */
+		this.fnSortListener = function( nNode, iColumn, fnCallback )
+		{
+			this.api( true ).order.listener( nNode, iColumn, fnCallback );
+		};
+		
+		
+		/**
+		 * Update a table cell or row - this method will accept either a single value to
+		 * update the cell with, an array of values with one element for each column or
+		 * an object in the same format as the original data source. The function is
+		 * self-referencing in order to make the multi column updates easier.
+		 *  @param {object|array|string} mData Data to update the cell/row with
+		 *  @param {node|int} mRow TR element you want to update or the aoData index
+		 *  @param {int} [iColumn] The column to update, give as null or undefined to
+		 *    update a whole row.
+		 *  @param {bool} [bRedraw=true] Redraw the table or not
+		 *  @param {bool} [bAction=true] Perform pre-draw actions or not
+		 *  @returns {int} 0 on success, 1 on error
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
+		 *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
+		 *    } );
+		 */
+		this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
+		{
+			var api = this.api( true );
+		
+			if ( iColumn === undefined || iColumn === null ) {
+				api.row( mRow ).data( mData );
+			}
+			else {
+				api.cell( mRow, iColumn ).data( mData );
+			}
+		
+			if ( bAction === undefined || bAction ) {
+				api.columns.adjust();
+			}
+		
+			if ( bRedraw === undefined || bRedraw ) {
+				api.draw();
+			}
+			return 0;
+		};
+		
+		
+		/**
+		 * Provide a common method for plug-ins to check the version of DataTables being used, in order
+		 * to ensure compatibility.
+		 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
+		 *    formats "X" and "X.Y" are also acceptable.
+		 *  @returns {boolean} true if this version of DataTables is greater or equal to the required
+		 *    version, or false if this version of DataTales is not suitable
+		 *  @method
+		 *  @dtopt API
+		 *  @deprecated Since v1.10
+		 *
+		 *  @example
+		 *    $(document).ready(function() {
+		 *      var oTable = $('#example').dataTable();
+		 *      alert( oTable.fnVersionCheck( '1.9.0' ) );
+		 *    } );
+		 */
+		this.fnVersionCheck = _ext.fnVersionCheck;
+		
+
+		var _that = this;
+		var emptyInit = options === undefined;
+		var len = this.length;
+
+		if ( emptyInit ) {
+			options = {};
+		}
+
+		this.oApi = this.internal = _ext.internal;
+
+		// Extend with old style plug-in API methods
+		for ( var fn in DataTable.ext.internal ) {
+			if ( fn ) {
+				this[fn] = _fnExternApiFunc(fn);
+			}
+		}
+
+		this.each(function() {
+			// For each initialisation we want to give it a clean initialisation
+			// object that can be bashed around
+			var o = {};
+			var oInit = len > 1 ? // optimisation for single table case
+				_fnExtend( o, options, true ) :
+				options;
+
+			/*global oInit,_that,emptyInit*/
+			var i=0, iLen, j, jLen, k, kLen;
+			var sId = this.getAttribute( 'id' );
+			var bInitHandedOff = false;
+			var defaults = DataTable.defaults;
+			var $this = $(this);
+			
+			
+			/* Sanity check */
+			if ( this.nodeName.toLowerCase() != 'table' )
+			{
+				_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
+				return;
+			}
+			
+			/* Backwards compatibility for the defaults */
+			_fnCompatOpts( defaults );
+			_fnCompatCols( defaults.column );
+			
+			/* Convert the camel-case defaults to Hungarian */
+			_fnCamelToHungarian( defaults, defaults, true );
+			_fnCamelToHungarian( defaults.column, defaults.column, true );
+			
+			/* Setting up the initialisation object */
+			_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
+			
+			
+			
+			/* Check to see if we are re-initialising a table */
+			var allSettings = DataTable.settings;
+			for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
+			{
+				var s = allSettings[i];
+			
+				/* Base check on table node */
+				if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
+				{
+					var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
+					var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
+			
+					if ( emptyInit || bRetrieve )
+					{
+						return s.oInstance;
+					}
+					else if ( bDestroy )
+					{
+						s.oInstance.fnDestroy();
+						break;
+					}
+					else
+					{
+						_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
+						return;
+					}
+				}
+			
+				/* If the element we are initialising has the same ID as a table which was previously
+				 * initialised, but the table nodes don't match (from before) then we destroy the old
+				 * instance by simply deleting it. This is under the assumption that the table has been
+				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
+				 */
+				if ( s.sTableId == this.id )
+				{
+					allSettings.splice( i, 1 );
+					break;
+				}
+			}
+			
+			/* Ensure the table has an ID - required for accessibility */
+			if ( sId === null || sId === "" )
+			{
+				sId = "DataTables_Table_"+(DataTable.ext._unique++);
+				this.id = sId;
+			}
+			
+			/* Create the settings object for this table and set some of the default parameters */
+			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
+				"sDestroyWidth": $this[0].style.width,
+				"sInstance":     sId,
+				"sTableId":      sId
+			} );
+			oSettings.nTable = this;
+			oSettings.oApi   = _that.internal;
+			oSettings.oInit  = oInit;
+			
+			allSettings.push( oSettings );
+			
+			// Need to add the instance after the instance after the settings object has been added
+			// to the settings array, so we can self reference the table instance if more than one
+			oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
+			
+			// Backwards compatibility, before we apply all the defaults
+			_fnCompatOpts( oInit );
+			
+			if ( oInit.oLanguage )
+			{
+				_fnLanguageCompat( oInit.oLanguage );
+			}
+			
+			// If the length menu is given, but the init display length is not, use the length menu
+			if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
+			{
+				oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
+					oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
+			}
+			
+			// Apply the defaults and init options to make a single init object will all
+			// options defined from defaults and instance options.
+			oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
+			
+			
+			// Map the initialisation options onto the settings object
+			_fnMap( oSettings.oFeatures, oInit, [
+				"bPaginate",
+				"bLengthChange",
+				"bFilter",
+				"bSort",
+				"bSortMulti",
+				"bInfo",
+				"bProcessing",
+				"bAutoWidth",
+				"bSortClasses",
+				"bServerSide",
+				"bDeferRender"
+			] );
+			_fnMap( oSettings, oInit, [
+				"asStripeClasses",
+				"ajax",
+				"fnServerData",
+				"fnFormatNumber",
+				"sServerMethod",
+				"aaSorting",
+				"aaSortingFixed",
+				"aLengthMenu",
+				"sPaginationType",
+				"sAjaxSource",
+				"sAjaxDataProp",
+				"iStateDuration",
+				"sDom",
+				"bSortCellsTop",
+				"iTabIndex",
+				"fnStateLoadCallback",
+				"fnStateSaveCallback",
+				"renderer",
+				"searchDelay",
+				[ "iCookieDuration", "iStateDuration" ], // backwards compat
+				[ "oSearch", "oPreviousSearch" ],
+				[ "aoSearchCols", "aoPreSearchCols" ],
+				[ "iDisplayLength", "_iDisplayLength" ],
+				[ "bJQueryUI", "bJUI" ]
+			] );
+			_fnMap( oSettings.oScroll, oInit, [
+				[ "sScrollX", "sX" ],
+				[ "sScrollXInner", "sXInner" ],
+				[ "sScrollY", "sY" ],
+				[ "bScrollCollapse", "bCollapse" ]
+			] );
+			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
+			
+			/* Callback functions which are array driven */
+			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );
+			_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );
+			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );
+			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );
+			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );
+			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );
+			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );
+			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );
+			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );
+			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );
+			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );
+			
+			var oClasses = oSettings.oClasses;
+			
+			// @todo Remove in 1.11
+			if ( oInit.bJQueryUI )
+			{
+				/* Use the JUI classes object for display. You could clone the oStdClasses object if
+				 * you want to have multiple tables with multiple independent classes
+				 */
+				$.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
+			
+				if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
+				{
+					/* Set the DOM to use a layout suitable for jQuery UI's theming */
+					oSettings.sDom = '<"H"lfr>t<"F"ip>';
+				}
+			
+				if ( ! oSettings.renderer ) {
+					oSettings.renderer = 'jqueryui';
+				}
+				else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
+					oSettings.renderer.header = 'jqueryui';
+				}
+			}
+			else
+			{
+				$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
+			}
+			$this.addClass( oClasses.sTable );
+			
+			/* Calculate the scroll bar width and cache it for use later on */
+			if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
+			{
+				oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
+			}
+			if ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling
+				oSettings.oScroll.sX = '100%';
+			}
+			
+			if ( oSettings.iInitDisplayStart === undefined )
+			{
+				/* Display start point, taking into account the save saving */
+				oSettings.iInitDisplayStart = oInit.iDisplayStart;
+				oSettings._iDisplayStart = oInit.iDisplayStart;
+			}
+			
+			if ( oInit.iDeferLoading !== null )
+			{
+				oSettings.bDeferLoading = true;
+				var tmp = $.isArray( oInit.iDeferLoading );
+				oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
+				oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
+			}
+			
+			/* Language definitions */
+			var oLanguage = oSettings.oLanguage;
+			$.extend( true, oLanguage, oInit.oLanguage );
+			
+			if ( oLanguage.sUrl !== "" )
+			{
+				/* Get the language definitions from a file - because this Ajax call makes the language
+				 * get async to the remainder of this function we use bInitHandedOff to indicate that
+				 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
+				 */
+				$.ajax( {
+					dataType: 'json',
+					url: oLanguage.sUrl,
+					success: function ( json ) {
+						_fnLanguageCompat( json );
+						_fnCamelToHungarian( defaults.oLanguage, json );
+						$.extend( true, oLanguage, json );
+						_fnInitialise( oSettings );
+					},
+					error: function () {
+						// Error occurred loading language file, continue on as best we can
+						_fnInitialise( oSettings );
+					}
+				} );
+				bInitHandedOff = true;
+			}
+			
+			/*
+			 * Stripes
+			 */
+			if ( oInit.asStripeClasses === null )
+			{
+				oSettings.asStripeClasses =[
+					oClasses.sStripeOdd,
+					oClasses.sStripeEven
+				];
+			}
+			
+			/* Remove row stripe classes if they are already on the table row */
+			var stripeClasses = oSettings.asStripeClasses;
+			var rowOne = $this.children('tbody').find('tr').eq(0);
+			if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
+				return rowOne.hasClass(el);
+			} ) ) !== -1 ) {
+				$('tbody tr', this).removeClass( stripeClasses.join(' ') );
+				oSettings.asDestroyStripes = stripeClasses.slice();
+			}
+			
+			/*
+			 * Columns
+			 * See if we should load columns automatically or use defined ones
+			 */
+			var anThs = [];
+			var aoColumnsInit;
+			var nThead = this.getElementsByTagName('thead');
+			if ( nThead.length !== 0 )
+			{
+				_fnDetectHeader( oSettings.aoHeader, nThead[0] );
+				anThs = _fnGetUniqueThs( oSettings );
+			}
+			
+			/* If not given a column array, generate one with nulls */
+			if ( oInit.aoColumns === null )
+			{
+				aoColumnsInit = [];
+				for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
+				{
+					aoColumnsInit.push( null );
+				}
+			}
+			else
+			{
+				aoColumnsInit = oInit.aoColumns;
+			}
+			
+			/* Add the columns */
+			for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
+			{
+				_fnAddColumn( oSettings, anThs ? anThs[i] : null );
+			}
+			
+			/* Apply the column definitions */
+			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
+				_fnColumnOptions( oSettings, iCol, oDef );
+			} );
+			
+			/* HTML5 attribute detection - build an mData object automatically if the
+			 * attributes are found
+			 */
+			if ( rowOne.length ) {
+				var a = function ( cell, name ) {
+					return cell.getAttribute( 'data-'+name ) !== null ? name : null;
+				};
+			
+				$.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {
+					var col = oSettings.aoColumns[i];
+			
+					if ( col.mData === i ) {
+						var sort = a( cell, 'sort' ) || a( cell, 'order' );
+						var filter = a( cell, 'filter' ) || a( cell, 'search' );
+			
+						if ( sort !== null || filter !== null ) {
+							col.mData = {
+								_:      i+'.display',
+								sort:   sort !== null   ? i+'.@data-'+sort   : undefined,
+								type:   sort !== null   ? i+'.@data-'+sort   : undefined,
+								filter: filter !== null ? i+'.@data-'+filter : undefined
+							};
+			
+							_fnColumnOptions( oSettings, i );
+						}
+					}
+				} );
+			}
+			
+			var features = oSettings.oFeatures;
+			
+			/* Must be done after everything which can be overridden by the state saving! */
+			if ( oInit.bStateSave )
+			{
+				features.bStateSave = true;
+				_fnLoadState( oSettings, oInit );
+				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
+			}
+			
+			
+			/*
+			 * Sorting
+			 * @todo For modularisation (1.11) this needs to do into a sort start up handler
+			 */
+			
+			// If aaSorting is not defined, then we use the first indicator in asSorting
+			// in case that has been altered, so the default sort reflects that option
+			if ( oInit.aaSorting === undefined )
+			{
+				var sorting = oSettings.aaSorting;
+				for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
+				{
+					sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
+				}
+			}
+			
+			/* Do a first pass on the sorting classes (allows any size changes to be taken into
+			 * account, and also will apply sorting disabled classes if disabled
+			 */
+			_fnSortingClasses( oSettings );
+			
+			if ( features.bSort )
+			{
+				_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
+					if ( oSettings.bSorted ) {
+						var aSort = _fnSortFlatten( oSettings );
+						var sortedColumns = {};
+			
+						$.each( aSort, function (i, val) {
+							sortedColumns[ val.src ] = val.dir;
+						} );
+			
+						_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
+						_fnSortAria( oSettings );
+					}
+				} );
+			}
+			
+			_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
+				if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
+					_fnSortingClasses( oSettings );
+				}
+			}, 'sc' );
+			
+			
+			/*
+			 * Final init
+			 * Cache the header, body and footer as required, creating them if needed
+			 */
+			
+			/* Browser support detection */
+			_fnBrowserDetect( oSettings );
+			
+			// Work around for Webkit bug 83867 - store the caption-side before removing from doc
+			var captions = $this.children('caption').each( function () {
+				this._captionSide = $this.css('caption-side');
+			} );
+			
+			var thead = $this.children('thead');
+			if ( thead.length === 0 )
+			{
+				thead = $('<thead/>').appendTo(this);
+			}
+			oSettings.nTHead = thead[0];
+			
+			var tbody = $this.children('tbody');
+			if ( tbody.length === 0 )
+			{
+				tbody = $('<tbody/>').appendTo(this);
+			}
+			oSettings.nTBody = tbody[0];
+			
+			var tfoot = $this.children('tfoot');
+			if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
+			{
+				// If we are a scrolling table, and no footer has been given, then we need to create
+				// a tfoot element for the caption element to be appended to
+				tfoot = $('<tfoot/>').appendTo(this);
+			}
+			
+			if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
+				$this.addClass( oClasses.sNoFooter );
+			}
+			else if ( tfoot.length > 0 ) {
+				oSettings.nTFoot = tfoot[0];
+				_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
+			}
+			
+			/* Check if there is data passing into the constructor */
+			if ( oInit.aaData )
+			{
+				for ( i=0 ; i<oInit.aaData.length ; i++ )
+				{
+					_fnAddData( oSettings, oInit.aaData[ i ] );
+				}
+			}
+			else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
+			{
+				/* Grab the data from the page - only do this when deferred loading or no Ajax
+				 * source since there is no point in reading the DOM data if we are then going
+				 * to replace it with Ajax data
+				 */
+				_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
+			}
+			
+			/* Copy the data index array */
+			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+			
+			/* Initialisation complete - table can be drawn */
+			oSettings.bInitialised = true;
+			
+			/* Check if we need to initialise the table (it might not have been handed off to the
+			 * language processor)
+			 */
+			if ( bInitHandedOff === false )
+			{
+				_fnInitialise( oSettings );
+			}
+		} );
+		_that = null;
+		return this;
+	};
+
+	
+	
+	/**
+	 * Computed structure of the DataTables API, defined by the options passed to
+	 * `DataTable.Api.register()` when building the API.
+	 *
+	 * The structure is built in order to speed creation and extension of the Api
+	 * objects since the extensions are effectively pre-parsed.
+	 *
+	 * The array is an array of objects with the following structure, where this
+	 * base array represents the Api prototype base:
+	 *
+	 *     [
+	 *       {
+	 *         name:      'data'                -- string   - Property name
+	 *         val:       function () {},       -- function - Api method (or undefined if just an object
+	 *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
+	 *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
+	 *       },
+	 *       {
+	 *         name:     'row'
+	 *         val:       {},
+	 *         methodExt: [ ... ],
+	 *         propExt:   [
+	 *           {
+	 *             name:      'data'
+	 *             val:       function () {},
+	 *             methodExt: [ ... ],
+	 *             propExt:   [ ... ]
+	 *           },
+	 *           ...
+	 *         ]
+	 *       }
+	 *     ]
+	 *
+	 * @type {Array}
+	 * @ignore
+	 */
+	var __apiStruct = [];
+	
+	
+	/**
+	 * `Array.prototype` reference.
+	 *
+	 * @type object
+	 * @ignore
+	 */
+	var __arrayProto = Array.prototype;
+	
+	
+	/**
+	 * Abstraction for `context` parameter of the `Api` constructor to allow it to
+	 * take several different forms for ease of use.
+	 *
+	 * Each of the input parameter types will be converted to a DataTables settings
+	 * object where possible.
+	 *
+	 * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
+	 *   of:
+	 *
+	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
+	 *     with be found and used.
+	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
+	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
+	 *   * `object` - DataTables settings object
+	 *   * `DataTables.Api` - API instance
+	 * @return {array|null} Matching DataTables settings objects. `null` or
+	 *   `undefined` is returned if no matching DataTable is found.
+	 * @ignore
+	 */
+	var _toSettings = function ( mixed )
+	{
+		var idx, jq;
+		var settings = DataTable.settings;
+		var tables = $.map( settings, function (el, i) {
+			return el.nTable;
+		} );
+	
+		if ( ! mixed ) {
+			return [];
+		}
+		else if ( mixed.nTable && mixed.oApi ) {
+			// DataTables settings object
+			return [ mixed ];
+		}
+		else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
+			// Table node
+			idx = $.inArray( mixed, tables );
+			return idx !== -1 ? [ settings[idx] ] : null;
+		}
+		else if ( mixed && typeof mixed.settings === 'function' ) {
+			return mixed.settings().toArray();
+		}
+		else if ( typeof mixed === 'string' ) {
+			// jQuery selector
+			jq = $(mixed);
+		}
+		else if ( mixed instanceof $ ) {
+			// jQuery object (also DataTables instance)
+			jq = mixed;
+		}
+	
+		if ( jq ) {
+			return jq.map( function(i) {
+				idx = $.inArray( this, tables );
+				return idx !== -1 ? settings[idx] : null;
+			} ).toArray();
+		}
+	};
+	
+	
+	/**
+	 * DataTables API class - used to control and interface with  one or more
+	 * DataTables enhanced tables.
+	 *
+	 * The API class is heavily based on jQuery, presenting a chainable interface
+	 * that you can use to interact with tables. Each instance of the API class has
+	 * a "context" - i.e. the tables that it will operate on. This could be a single
+	 * table, all tables on a page or a sub-set thereof.
+	 *
+	 * Additionally the API is designed to allow you to easily work with the data in
+	 * the tables, retrieving and manipulating it as required. This is done by
+	 * presenting the API class as an array like interface. The contents of the
+	 * array depend upon the actions requested by each method (for example
+	 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
+	 * return an array of objects or arrays depending upon your table's
+	 * configuration). The API object has a number of array like methods (`push`,
+	 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
+	 * `unique` etc) to assist your working with the data held in a table.
+	 *
+	 * Most methods (those which return an Api instance) are chainable, which means
+	 * the return from a method call also has all of the methods available that the
+	 * top level object had. For example, these two calls are equivalent:
+	 *
+	 *     // Not chained
+	 *     api.row.add( {...} );
+	 *     api.draw();
+	 *
+	 *     // Chained
+	 *     api.row.add( {...} ).draw();
+	 *
+	 * @class DataTable.Api
+	 * @param {array|object|string|jQuery} context DataTable identifier. This is
+	 *   used to define which DataTables enhanced tables this API will operate on.
+	 *   Can be one of:
+	 *
+	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
+	 *     with be found and used.
+	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
+	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
+	 *   * `object` - DataTables settings object
+	 * @param {array} [data] Data to initialise the Api instance with.
+	 *
+	 * @example
+	 *   // Direct initialisation during DataTables construction
+	 *   var api = $('#example').DataTable();
+	 *
+	 * @example
+	 *   // Initialisation using a DataTables jQuery object
+	 *   var api = $('#example').dataTable().api();
+	 *
+	 * @example
+	 *   // Initialisation as a constructor
+	 *   var api = new $.fn.DataTable.Api( 'table.dataTable' );
+	 */
+	_Api = function ( context, data )
+	{
+		if ( ! (this instanceof _Api) ) {
+			return new _Api( context, data );
+		}
+	
+		var settings = [];
+		var ctxSettings = function ( o ) {
+			var a = _toSettings( o );
+			if ( a ) {
+				settings.push.apply( settings, a );
+			}
+		};
+	
+		if ( $.isArray( context ) ) {
+			for ( var i=0, ien=context.length ; i<ien ; i++ ) {
+				ctxSettings( context[i] );
+			}
+		}
+		else {
+			ctxSettings( context );
+		}
+	
+		// Remove duplicates
+		this.context = _unique( settings );
+	
+		// Initial data
+		if ( data ) {
+			this.push.apply( this, data.toArray ? data.toArray() : data );
+		}
+	
+		// selector
+		this.selector = {
+			rows: null,
+			cols: null,
+			opts: null
+		};
+	
+		_Api.extend( this, this, __apiStruct );
+	};
+	
+	DataTable.Api = _Api;
+	
+	_Api.prototype = /** @lends DataTables.Api */{
+		any: function ()
+		{
+			return this.flatten().length !== 0;
+		},
+	
+	
+		concat:  __arrayProto.concat,
+	
+	
+		context: [], // array of table settings objects
+	
+	
+		each: function ( fn )
+		{
+			for ( var i=0, ien=this.length ; i<ien; i++ ) {
+				fn.call( this, this[i], i, this );
+			}
+	
+			return this;
+		},
+	
+	
+		eq: function ( idx )
+		{
+			var ctx = this.context;
+	
+			return ctx.length > idx ?
+				new _Api( ctx[idx], this[idx] ) :
+				null;
+		},
+	
+	
+		filter: function ( fn )
+		{
+			var a = [];
+	
+			if ( __arrayProto.filter ) {
+				a = __arrayProto.filter.call( this, fn, this );
+			}
+			else {
+				// Compatibility for browsers without EMCA-252-5 (JS 1.6)
+				for ( var i=0, ien=this.length ; i<ien ; i++ ) {
+					if ( fn.call( this, this[i], i, this ) ) {
+						a.push( this[i] );
+					}
+				}
+			}
+	
+			return new _Api( this.context, a );
+		},
+	
+	
+		flatten: function ()
+		{
+			var a = [];
+			return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
+		},
+	
+	
+		join:    __arrayProto.join,
+	
+	
+		indexOf: __arrayProto.indexOf || function (obj, start)
+		{
+			for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
+				if ( this[i] === obj ) {
+					return i;
+				}
+			}
+			return -1;
+		},
+	
+		iterator: function ( flatten, type, fn, alwaysNew ) {
+			var
+				a = [], ret,
+				i, ien, j, jen,
+				context = this.context,
+				rows, items, item,
+				selector = this.selector;
+	
+			// Argument shifting
+			if ( typeof flatten === 'string' ) {
+				alwaysNew = fn;
+				fn = type;
+				type = flatten;
+				flatten = false;
+			}
+	
+			for ( i=0, ien=context.length ; i<ien ; i++ ) {
+				var apiInst = new _Api( context[i] );
+	
+				if ( type === 'table' ) {
+					ret = fn.call( apiInst, context[i], i );
+	
+					if ( ret !== undefined ) {
+						a.push( ret );
+					}
+				}
+				else if ( type === 'columns' || type === 'rows' ) {
+					// this has same length as context - one entry for each table
+					ret = fn.call( apiInst, context[i], this[i], i );
+	
+					if ( ret !== undefined ) {
+						a.push( ret );
+					}
+				}
+				else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
+					// columns and rows share the same structure.
+					// 'this' is an array of column indexes for each context
+					items = this[i];
+	
+					if ( type === 'column-rows' ) {
+						rows = _selector_row_indexes( context[i], selector.opts );
+					}
+	
+					for ( j=0, jen=items.length ; j<jen ; j++ ) {
+						item = items[j];
+	
+						if ( type === 'cell' ) {
+							ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
+						}
+						else {
+							ret = fn.call( apiInst, context[i], item, i, j, rows );
+						}
+	
+						if ( ret !== undefined ) {
+							a.push( ret );
+						}
+					}
+				}
+			}
+	
+			if ( a.length || alwaysNew ) {
+				var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
+				var apiSelector = api.selector;
+				apiSelector.rows = selector.rows;
+				apiSelector.cols = selector.cols;
+				apiSelector.opts = selector.opts;
+				return api;
+			}
+			return this;
+		},
+	
+	
+		lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
+		{
+			// Bit cheeky...
+			return this.indexOf.apply( this.toArray.reverse(), arguments );
+		},
+	
+	
+		length:  0,
+	
+	
+		map: function ( fn )
+		{
+			var a = [];
+	
+			if ( __arrayProto.map ) {
+				a = __arrayProto.map.call( this, fn, this );
+			}
+			else {
+				// Compatibility for browsers without EMCA-252-5 (JS 1.6)
+				for ( var i=0, ien=this.length ; i<ien ; i++ ) {
+					a.push( fn.call( this, this[i], i ) );
+				}
+			}
+	
+			return new _Api( this.context, a );
+		},
+	
+	
+		pluck: function ( prop )
+		{
+			return this.map( function ( el ) {
+				return el[ prop ];
+			} );
+		},
+	
+		pop:     __arrayProto.pop,
+	
+	
+		push:    __arrayProto.push,
+	
+	
+		// Does not return an API instance
+		reduce: __arrayProto.reduce || function ( fn, init )
+		{
+			return _fnReduce( this, fn, init, 0, this.length, 1 );
+		},
+	
+	
+		reduceRight: __arrayProto.reduceRight || function ( fn, init )
+		{
+			return _fnReduce( this, fn, init, this.length-1, -1, -1 );
+		},
+	
+	
+		reverse: __arrayProto.reverse,
+	
+	
+		// Object with rows, columns and opts
+		selector: null,
+	
+	
+		shift:   __arrayProto.shift,
+	
+	
+		sort:    __arrayProto.sort, // ? name - order?
+	
+	
+		splice:  __arrayProto.splice,
+	
+	
+		toArray: function ()
+		{
+			return __arrayProto.slice.call( this );
+		},
+	
+	
+		to$: function ()
+		{
+			return $( this );
+		},
+	
+	
+		toJQuery: function ()
+		{
+			return $( this );
+		},
+	
+	
+		unique: function ()
+		{
+			return new _Api( this.context, _unique(this) );
+		},
+	
+	
+		unshift: __arrayProto.unshift
+	};
+	
+	
+	_Api.extend = function ( scope, obj, ext )
+	{
+		// Only extend API instances and static properties of the API
+		if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
+			return;
+		}
+	
+		var
+			i, ien,
+			j, jen,
+			struct, inner,
+			methodScoping = function ( scope, fn, struc ) {
+				return function () {
+					var ret = fn.apply( scope, arguments );
+	
+					// Method extension
+					_Api.extend( ret, ret, struc.methodExt );
+					return ret;
+				};
+			};
+	
+		for ( i=0, ien=ext.length ; i<ien ; i++ ) {
+			struct = ext[i];
+	
+			// Value
+			obj[ struct.name ] = typeof struct.val === 'function' ?
+				methodScoping( scope, struct.val, struct ) :
+				$.isPlainObject( struct.val ) ?
+					{} :
+					struct.val;
+	
+			obj[ struct.name ].__dt_wrapper = true;
+	
+			// Property extension
+			_Api.extend( scope, obj[ struct.name ], struct.propExt );
+		}
+	};
+	
+	
+	// @todo - Is there need for an augment function?
+	// _Api.augment = function ( inst, name )
+	// {
+	// 	// Find src object in the structure from the name
+	// 	var parts = name.split('.');
+	
+	// 	_Api.extend( inst, obj );
+	// };
+	
+	
+	//     [
+	//       {
+	//         name:      'data'                -- string   - Property name
+	//         val:       function () {},       -- function - Api method (or undefined if just an object
+	//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
+	//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
+	//       },
+	//       {
+	//         name:     'row'
+	//         val:       {},
+	//         methodExt: [ ... ],
+	//         propExt:   [
+	//           {
+	//             name:      'data'
+	//             val:       function () {},
+	//             methodExt: [ ... ],
+	//             propExt:   [ ... ]
+	//           },
+	//           ...
+	//         ]
+	//       }
+	//     ]
+	
+	_Api.register = _api_register = function ( name, val )
+	{
+		if ( $.isArray( name ) ) {
+			for ( var j=0, jen=name.length ; j<jen ; j++ ) {
+				_Api.register( name[j], val );
+			}
+			return;
+		}
+	
+		var
+			i, ien,
+			heir = name.split('.'),
+			struct = __apiStruct,
+			key, method;
+	
+		var find = function ( src, name ) {
+			for ( var i=0, ien=src.length ; i<ien ; i++ ) {
+				if ( src[i].name === name ) {
+					return src[i];
+				}
+			}
+			return null;
+		};
+	
+		for ( i=0, ien=heir.length ; i<ien ; i++ ) {
+			method = heir[i].indexOf('()') !== -1;
+			key = method ?
+				heir[i].replace('()', '') :
+				heir[i];
+	
+			var src = find( struct, key );
+			if ( ! src ) {
+				src = {
+					name:      key,
+					val:       {},
+					methodExt: [],
+					propExt:   []
+				};
+				struct.push( src );
+			}
+	
+			if ( i === ien-1 ) {
+				src.val = val;
+			}
+			else {
+				struct = method ?
+					src.methodExt :
+					src.propExt;
+			}
+		}
+	};
+	
+	
+	_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
+		_Api.register( pluralName, val );
+	
+		_Api.register( singularName, function () {
+			var ret = val.apply( this, arguments );
+	
+			if ( ret === this ) {
+				// Returned item is the API instance that was passed in, return it
+				return this;
+			}
+			else if ( ret instanceof _Api ) {
+				// New API instance returned, want the value from the first item
+				// in the returned array for the singular result.
+				return ret.length ?
+					$.isArray( ret[0] ) ?
+						new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
+						ret[0] :
+					undefined;
+			}
+	
+			// Non-API return - just fire it back
+			return ret;
+		} );
+	};
+	
+	
+	/**
+	 * Selector for HTML tables. Apply the given selector to the give array of
+	 * DataTables settings objects.
+	 *
+	 * @param {string|integer} [selector] jQuery selector string or integer
+	 * @param  {array} Array of DataTables settings objects to be filtered
+	 * @return {array}
+	 * @ignore
+	 */
+	var __table_selector = function ( selector, a )
+	{
+		// Integer is used to pick out a table by index
+		if ( typeof selector === 'number' ) {
+			return [ a[ selector ] ];
+		}
+	
+		// Perform a jQuery selector on the table nodes
+		var nodes = $.map( a, function (el, i) {
+			return el.nTable;
+		} );
+	
+		return $(nodes)
+			.filter( selector )
+			.map( function (i) {
+				// Need to translate back from the table node to the settings
+				var idx = $.inArray( this, nodes );
+				return a[ idx ];
+			} )
+			.toArray();
+	};
+	
+	
+	
+	/**
+	 * Context selector for the API's context (i.e. the tables the API instance
+	 * refers to.
+	 *
+	 * @name    DataTable.Api#tables
+	 * @param {string|integer} [selector] Selector to pick which tables the iterator
+	 *   should operate on. If not given, all tables in the current context are
+	 *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
+	 *   select multiple tables or as an integer to select a single table.
+	 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
+	 */
+	_api_register( 'tables()', function ( selector ) {
+		// A new instance is created if there was a selector specified
+		return selector ?
+			new _Api( __table_selector( selector, this.context ) ) :
+			this;
+	} );
+	
+	
+	_api_register( 'table()', function ( selector ) {
+		var tables = this.tables( selector );
+		var ctx = tables.context;
+	
+		// Truncate to the first matched table
+		return ctx.length ?
+			new _Api( ctx[0] ) :
+			tables;
+	} );
+	
+	
+	_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
+		return this.iterator( 'table', function ( ctx ) {
+			return ctx.nTable;
+		}, 1 );
+	} );
+	
+	
+	_api_registerPlural( 'tables().body()', 'table().body()' , function () {
+		return this.iterator( 'table', function ( ctx ) {
+			return ctx.nTBody;
+		}, 1 );
+	} );
+	
+	
+	_api_registerPlural( 'tables().header()', 'table().header()' , function () {
+		return this.iterator( 'table', function ( ctx ) {
+			return ctx.nTHead;
+		}, 1 );
+	} );
+	
+	
+	_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
+		return this.iterator( 'table', function ( ctx ) {
+			return ctx.nTFoot;
+		}, 1 );
+	} );
+	
+	
+	_api_registerPlural( 'tables().containers()', 'table().container()' , function () {
+		return this.iterator( 'table', function ( ctx ) {
+			return ctx.nTableWrapper;
+		}, 1 );
+	} );
+	
+	
+	
+	/**
+	 * Redraw the tables in the current context.
+	 *
+	 * @param {boolean} [reset=true] Reset (default) or hold the current paging
+	 *   position. A full re-sort and re-filter is performed when this method is
+	 *   called, which is why the pagination reset is the default action.
+	 * @returns {DataTables.Api} this
+	 */
+	_api_register( 'draw()', function ( resetPaging ) {
+		return this.iterator( 'table', function ( settings ) {
+			_fnReDraw( settings, resetPaging===false );
+		} );
+	} );
+	
+	
+	
+	/**
+	 * Get the current page index.
+	 *
+	 * @return {integer} Current page index (zero based)
+	 *//**
+	 * Set the current page.
+	 *
+	 * Note that if you attempt to show a page which does not exist, DataTables will
+	 * not throw an error, but rather reset the paging.
+	 *
+	 * @param {integer|string} action The paging action to take. This can be one of:
+	 *  * `integer` - The page index to jump to
+	 *  * `string` - An action to take:
+	 *    * `first` - Jump to first page.
+	 *    * `next` - Jump to the next page
+	 *    * `previous` - Jump to previous page
+	 *    * `last` - Jump to the last page.
+	 * @returns {DataTables.Api} this
+	 */
+	_api_register( 'page()', function ( action ) {
+		if ( action === undefined ) {
+			return this.page.info().page; // not an expensive call
+		}
+	
+		// else, have an action to take on all tables
+		return this.iterator( 'table', function ( settings ) {
+			_fnPageChange( settings, action );
+		} );
+	} );
+	
+	
+	/**
+	 * Paging information for the first table in the current context.
+	 *
+	 * If you require paging information for another table, use the `table()` method
+	 * with a suitable selector.
+	 *
+	 * @return {object} Object with the following properties set:
+	 *  * `page` - Current page index (zero based - i.e. the first page is `0`)
+	 *  * `pages` - Total number of pages
+	 *  * `start` - Display index for the first record shown on the current page
+	 *  * `end` - Display index for the last record shown on the current page
+	 *  * `length` - Display length (number of records). Note that generally `start
+	 *    + length = end`, but this is not always true, for example if there are
+	 *    only 2 records to show on the final page, with a length of 10.
+	 *  * `recordsTotal` - Full data set length
+	 *  * `recordsDisplay` - Data set length once the current filtering criterion
+	 *    are applied.
+	 */
+	_api_register( 'page.info()', function ( action ) {
+		if ( this.context.length === 0 ) {
+			return undefined;
+		}
+	
+		var
+			settings   = this.context[0],
+			start      = settings._iDisplayStart,
+			len        = settings._iDisplayLength,
+			visRecords = settings.fnRecordsDisplay(),
+			all        = len === -1;
+	
+		return {
+			"page":           all ? 0 : Math.floor( start / len ),
+			"pages":          all ? 1 : Math.ceil( visRecords / len ),
+			"start":          start,
+			"end":            settings.fnDisplayEnd(),
+			"length":         len,
+			"recordsTotal":   settings.fnRecordsTotal(),
+			"recordsDisplay": visRecords
+		};
+	} );
+	
+	
+	/**
+	 * Get the current page length.
+	 *
+	 * @return {integer} Current page length. Note `-1` indicates that all records
+	 *   are to be shown.
+	 *//**
+	 * Set the current page length.
+	 *
+	 * @param {integer} Page length to set. Use `-1` to show all records.
+	 * @returns {DataTables.Api} this
+	 */
+	_api_register( 'page.len()', function ( len ) {
+		// Note that we can't call this function 'length()' because `length`
+		// is a Javascript property of functions which defines how many arguments
+		// the function expects.
+		if ( len === undefined ) {
+			return this.context.length !== 0 ?
+				this.context[0]._iDisplayLength :
+				undefined;
+		}
+	
+		// else, set the page length
+		return this.iterator( 'table', function ( settings ) {
+			_fnLengthChange( settings, len );
+		} );
+	} );
+	
+	
+	
+	var __reload = function ( settings, holdPosition, callback ) {
+		// Use the draw event to trigger a callback
+		if ( callback ) {
+			var api = new _Api( settings );
+	
+			api.one( 'draw', function () {
+				callback( api.ajax.json() );
+			} );
+		}
+	
+		if ( _fnDataSource( settings ) == 'ssp' ) {
+			_fnReDraw( settings, holdPosition );
+		}
+		else {
+			// Trigger xhr
+			_fnProcessingDisplay( settings, true );
+	
+			_fnBuildAjax( settings, [], function( json ) {
+				_fnClearTable( settings );
+	
+				var data = _fnAjaxDataSrc( settings, json );
+				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
+					_fnAddData( settings, data[i] );
+				}
+	
+				_fnReDraw( settings, holdPosition );
+				_fnProcessingDisplay( settings, false );
+			} );
+		}
+	};
+	
+	
+	/**
+	 * Get the JSON response from the last Ajax request that DataTables made to the
+	 * server. Note that this returns the JSON from the first table in the current
+	 * context.
+	 *
+	 * @return {object} JSON received from the server.
+	 */
+	_api_register( 'ajax.json()', function () {
+		var ctx = this.context;
+	
+		if ( ctx.length > 0 ) {
+			return ctx[0].json;
+		}
+	
+		// else return undefined;
+	} );
+	
+	
+	/**
+	 * Get the data submitted in the last Ajax request
+	 */
+	_api_register( 'ajax.params()', function () {
+		var ctx = this.context;
+	
+		if ( ctx.length > 0 ) {
+			return ctx[0].oAjaxData;
+		}
+	
+		// else return undefined;
+	} );
+	
+	
+	/**
+	 * Reload tables from the Ajax data source. Note that this function will
+	 * automatically re-draw the table when the remote data has been loaded.
+	 *
+	 * @param {boolean} [reset=true] Reset (default) or hold the current paging
+	 *   position. A full re-sort and re-filter is performed when this method is
+	 *   called, which is why the pagination reset is the default action.
+	 * @returns {DataTables.Api} this
+	 */
+	_api_register( 'ajax.reload()', function ( callback, resetPaging ) {
+		return this.iterator( 'table', function (settings) {
+			__reload( settings, resetPaging===false, callback );
+		} );
+	} );
+	
+	
+	/**
+	 * Get the current Ajax URL. Note that this returns the URL from the first
+	 * table in the current context.
+	 *
+	 * @return {string} Current Ajax source URL
+	 *//**
+	 * Set the Ajax URL. Note that this will set the URL for all tables in the
+	 * current context.
+	 *
+	 * @param {string} url URL to set.
+	 * @returns {DataTables.Api} this
+	 */
+	_api_register( 'ajax.url()', function ( url ) {
+		var ctx = this.context;
+	
+		if ( url === undefined ) {
+			// get
+			if ( ctx.length === 0 ) {
+				return undefined;
+			}
+			ctx = ctx[0];
+	
+			return ctx.ajax ?
+				$.isPlainObject( ctx.ajax ) ?
+					ctx.ajax.url :
+					ctx.ajax :
+				ctx.sAjaxSource;
+		}
+	
+		// set
+		return this.iterator( 'table', function ( settings ) {
+			if ( $.isPlainObject( settings.ajax ) ) {
+				settings.ajax.url = url;
+			}
+			else {
+				settings.ajax = url;
+			}
+			// No need to consider sAjaxSource here since DataTables gives priority
+			// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
+			// value of `sAjaxSource` redundant.
+		} );
+	} );
+	
+	
+	/**
+	 * Load data from the newly set Ajax URL. Note that this method is only
+	 * available when `ajax.url()` is used to set a URL. Additionally, this method
+	 * has the same effect as calling `ajax.reload()` but is provided for
+	 * convenience when setting a new URL. Like `ajax.reload()` it will
+	 * automatically redraw the table once the remote data has been loaded.
+	 *
+	 * @returns {DataTables.Api} this
+	 */
+	_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
+		// Same as a reload, but makes sense to present it for easy access after a
+		// url change
+		return this.iterator( 'table', function ( ctx ) {
+			__reload( ctx, resetPaging===false, callback );
+		} );
+	} );
+	
+	
+	
+	
+	var _selector_run = function ( type, selector, selectFn, settings, opts )
+	{
+		var
+			out = [], res,
+			a, i, ien, j, jen,
+			selectorType = typeof selector;
+	
+		// Can't just check for isArray here, as an API or jQuery instance might be
+		// given with their array like look
+		if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
+			selector = [ selector ];
+		}
+	
+		for ( i=0, ien=selector.length ; i<ien ; i++ ) {
+			a = selector[i] && selector[i].split ?
+				selector[i].split(',') :
+				[ selector[i] ];
+	
+			for ( j=0, jen=a.length ; j<jen ; j++ ) {
+				res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
+	
+				if ( res && res.length ) {
+					out.push.apply( out, res );
+				}
+			}
+		}
+	
+		// selector extensions
+		var ext = _ext.selector[ type ];
+		if ( ext.length ) {
+			for ( i=0, ien=ext.length ; i<ien ; i++ ) {
+				out = ext[i]( settings, opts, out );
+			}
+		}
+	
+		return out;
+	};
+	
+	
+	var _selector_opts = function ( opts )
+	{
+		if ( ! opts ) {
+			opts = {};
+		}
+	
+		// Backwards compatibility for 1.9- which used the terminology filter rather
+		// than search
+		if ( opts.filter && opts.search === undefined ) {
+			opts.search = opts.filter;
+		}
+	
+		return $.extend( {
+			search: 'none',
+			order: 'current',
+			page: 'all'
+		}, opts );
+	};
+	
+	
+	var _selector_first = function ( inst )
+	{
+		// Reduce the API instance to the first item found
+		for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
+			if ( inst[i].length > 0 ) {
+				// Assign the first element to the first item in the instance
+				// and truncate the instance and context
+				inst[0] = inst[i];
+				inst[0].length = 1;
+				inst.length = 1;
+				inst.context = [ inst.context[i] ];
+	
+				return inst;
+			}
+		}
+	
+		// Not found - return an empty instance
+		inst.length = 0;
+		return inst;
+	};
+	
+	
+	var _selector_row_indexes = function ( settings, opts )
+	{
+		var
+			i, ien, tmp, a=[],
+			displayFiltered = settings.aiDisplay,
+			displayMaster = settings.aiDisplayMaster;
+	
+		var
+			search = opts.search,  // none, applied, removed
+			order  = opts.order,   // applied, current, index (original - compatibility with 1.9)
+			page   = opts.page;    // all, current
+	
+		if ( _fnDataSource( settings ) == 'ssp' ) {
+			// In server-side processing mode, most options are irrelevant since
+			// rows not shown don't exist and the index order is the applied order
+			// Removed is a special case - for consistency just return an empty
+			// array
+			return search === 'removed' ?
+				[] :
+				_range( 0, displayMaster.length );
+		}
+		else if ( page == 'current' ) {
+			// Current page implies that order=current and fitler=applied, since it is
+			// fairly senseless otherwise, regardless of what order and search actually
+			// are
+			for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
+				a.push( displayFiltered[i] );
+			}
+		}
+		else if ( order == 'current' || order == 'applied' ) {
+			a = search == 'none' ?
+				displayMaster.slice() :                      // no search
+				search == 'applied' ?
+					displayFiltered.slice() :                // applied search
+					$.map( displayMaster, function (el, i) { // removed search
+						return $.inArray( el, displayFiltered ) === -1 ? el : null;
+					} );
+		}
+		else if ( order == 'index' || order == 'original' ) {
+			for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
+				if ( search == 'none' ) {
+					a.push( i );
+				}
+				else { // applied | removed
+					tmp = $.inArray( i, displayFiltered );
+	
+					if ((tmp === -1 && search == 'removed') ||
+						(tmp >= 0   && search == 'applied') )
+					{
+						a.push( i );
+					}
+				}
+			}
+		}
+	
+		return a;
+	};
+	
+	
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Rows
+	 *
+	 * {}          - no selector - use all available rows
+	 * {integer}   - row aoData index
+	 * {node}      - TR node
+	 * {string}    - jQuery selector to apply to the TR elements
+	 * {array}     - jQuery array of nodes, or simply an array of TR nodes
+	 *
+	 */
+	
+	
+	var __row_selector = function ( settings, selector, opts )
+	{
+		var run = function ( sel ) {
+			var selInt = _intVal( sel );
+			var i, ien;
+	
+			// Short cut - selector is a number and no options provided (default is
+			// all records, so no need to check if the index is in there, since it
+			// must be - dev error if the index doesn't exist).
+			if ( selInt !== null && ! opts ) {
+				return [ selInt ];
+			}
+	
+			var rows = _selector_row_indexes( settings, opts );
+	
+			if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
+				// Selector - integer
+				return [ selInt ];
+			}
+			else if ( ! sel ) {
+				// Selector - none
+				return rows;
+			}
+	
+			// Selector - function
+			if ( typeof sel === 'function' ) {
+				return $.map( rows, function (idx) {
+					var row = settings.aoData[ idx ];
+					return sel( idx, row._aData, row.nTr ) ? idx : null;
+				} );
+			}
+	
+			// Get nodes in the order from the `rows` array with null values removed
+			var nodes = _removeEmpty(
+				_pluck_order( settings.aoData, rows, 'nTr' )
+			);
+	
+			// Selector - node
+			if ( sel.nodeName ) {
+				if ( $.inArray( sel, nodes ) !== -1 ) {
+					return [ sel._DT_RowIndex ]; // sel is a TR node that is in the table
+					                             // and DataTables adds a prop for fast lookup
+				}
+			}
+	
+			// Selector - jQuery selector string, array of nodes or jQuery object/
+			// As jQuery's .filter() allows jQuery objects to be passed in filter,
+			// it also allows arrays, so this will cope with all three options
+			return $(nodes)
+				.filter( sel )
+				.map( function () {
+					return this._DT_RowIndex;
+				} )
+				.toArray();
+		};
+	
+		return _selector_run( 'row', selector, run, settings, opts );
+	};
+	
+	
+	_api_register( 'rows()', function ( selector, opts ) {
+		// argument shifting
+		if ( selector === undefined ) {
+			selector = '';
+		}
+		else if ( $.isPlainObject( selector ) ) {
+			opts = selector;
+			selector = '';
+		}
+	
+		opts = _selector_opts( opts );
+	
+		var inst = this.iterator( 'table', function ( settings ) {
+			return __row_selector( settings, selector, opts );
+		}, 1 );
+	
+		// Want argument shifting here and in __row_selector?
+		inst.selector.rows = selector;
+		inst.selector.opts = opts;
+	
+		return inst;
+	} );
+	
+	_api_register( 'rows().nodes()', function () {
+		return this.iterator( 'row', function ( settings, row ) {
+			return settings.aoData[ row ].nTr || undefined;
+		}, 1 );
+	} );
+	
+	_api_register( 'rows().data()', function () {
+		return this.iterator( true, 'rows', function ( settings, rows ) {
+			return _pluck_order( settings.aoData, rows, '_aData' );
+		}, 1 );
+	} );
+	
+	_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
+		return this.iterator( 'row', function ( settings, row ) {
+			var r = settings.aoData[ row ];
+			return type === 'search' ? r._aFilterData : r._aSortData;
+		}, 1 );
+	} );
+	
+	_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
+		return this.iterator( 'row', function ( settings, row ) {
+			_fnInvalidate( settings, row, src );
+		} );
+	} );
+	
+	_api_registerPlural( 'rows().indexes()', 'row().index()', function () {
+		return this.iterator( 'row', function ( settings, row ) {
+			return row;
+		}, 1 );
+	} );
+	
+	_api_registerPlural( 'rows().remove()', 'row().remove()', function () {
+		var that = this;
+	
+		return this.iterator( 'row', function ( settings, row, thatIdx ) {
+			var data = settings.aoData;
+	
+			data.splice( row, 1 );
+	
+			// Update the _DT_RowIndex parameter on all rows in the table
+			for ( var i=0, ien=data.length ; i<ien ; i++ ) {
+				if ( data[i].nTr !== null ) {
+					data[i].nTr._DT_RowIndex = i;
+				}
+			}
+	
+			// Remove the target row from the search array
+			var displayIndex = $.inArray( row, settings.aiDisplay );
+	
+			// Delete from the display arrays
+			_fnDeleteIndex( settings.aiDisplayMaster, row );
+			_fnDeleteIndex( settings.aiDisplay, row );
+			_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
+	
+			// Check for an 'overflow' they case for displaying the table
+			_fnLengthOverflow( settings );
+		} );
+	} );
+	
+	
+	_api_register( 'rows.add()', function ( rows ) {
+		var newRows = this.iterator( 'table', function ( settings ) {
+				var row, i, ien;
+				var out = [];
+	
+				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
+					row = rows[i];
+	
+					if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
+						out.push( _fnAddTr( settings, row )[0] );
+					}
+					else {
+						out.push( _fnAddData( settings, row ) );
+					}
+				}
+	
+				return out;
+			}, 1 );
+	
+		// Return an Api.rows() extended instance, so rows().nodes() etc can be used
+		var modRows = this.rows( -1 );
+		modRows.pop();
+		modRows.push.apply( modRows, newRows.toArray() );
+	
+		return modRows;
+	} );
+	
+	
+	
+	
+	
+	/**
+	 *
+	 */
+	_api_register( 'row()', function ( selector, opts ) {
+		return _selector_first( this.rows( selector, opts ) );
+	} );
+	
+	
+	_api_register( 'row().data()', function ( data ) {
+		var ctx = this.context;
+	
+		if ( data === undefined ) {
+			// Get
+			return ctx.length && this.length ?
+				ctx[0].aoData[ this[0] ]._aData :
+				undefined;
+		}
+	
+		// Set
+		ctx[0].aoData[ this[0] ]._aData = data;
+	
+		// Automatically invalidate
+		_fnInvalidate( ctx[0], this[0], 'data' );
+	
+		return this;
+	} );
+	
+	
+	_api_register( 'row().node()', function () {
+		var ctx = this.context;
+	
+		return ctx.length && this.length ?
+			ctx[0].aoData[ this[0] ].nTr || null :
+			null;
+	} );
+	
+	
+	_api_register( 'row.add()', function ( row ) {
+		// Allow a jQuery object to be passed in - only a single row is added from
+		// it though - the first element in the set
+		if ( row instanceof $ && row.length ) {
+			row = row[0];
+		}
+	
+		var rows = this.iterator( 'table', function ( settings ) {
+			if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
+				return _fnAddTr( settings, row )[0];
+			}
+			return _fnAddData( settings, row );
+		} );
+	
+		// Return an Api.rows() extended instance, with the newly added row selected
+		return this.row( rows[0] );
+	} );
+	
+	
+	
+	var __details_add = function ( ctx, row, data, klass )
+	{
+		// Convert to array of TR elements
+		var rows = [];
+		var addRow = function ( r, k ) {
+			// Recursion to allow for arrays of jQuery objects
+			if ( $.isArray( r ) || r instanceof $ ) {
+				for ( var i=0, ien=r.length ; i<ien ; i++ ) {
+					addRow( r[i], k );
+				}
+				return;
+			}
+	
+			// If we get a TR element, then just add it directly - up to the dev
+			// to add the correct number of columns etc
+			if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
+				rows.push( r );
+			}
+			else {
+				// Otherwise create a row with a wrapper
+				var created = $('<tr><td/></tr>').addClass( k );
+				$('td', created)
+					.addClass( k )
+					.html( r )
+					[0].colSpan = _fnVisbleColumns( ctx );
+	
+				rows.push( created[0] );
+			}
+		};
+	
+		addRow( data, klass );
+	
+		if ( row._details ) {
+			row._details.remove();
+		}
+	
+		row._details = $(rows);
+	
+		// If the children were already shown, that state should be retained
+		if ( row._detailsShow ) {
+			row._details.insertAfter( row.nTr );
+		}
+	};
+	
+	
+	var __details_remove = function ( api, idx )
+	{
+		var ctx = api.context;
+	
+		if ( ctx.length ) {
+			var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
+	
+			if ( row._details ) {
+				row._details.remove();
+	
+				row._detailsShow = undefined;
+				row._details = undefined;
+			}
+		}
+	};
+	
+	
+	var __details_display = function ( api, show ) {
+		var ctx = api.context;
+	
+		if ( ctx.length && api.length ) {
+			var row = ctx[0].aoData[ api[0] ];
+	
+			if ( row._details ) {
+				row._detailsShow = show;
+	
+				if ( show ) {
+					row._details.insertAfter( row.nTr );
+				}
+				else {
+					row._details.detach();
+				}
+	
+				__details_events( ctx[0] );
+			}
+		}
+	};
+	
+	
+	var __details_events = function ( settings )
+	{
+		var api = new _Api( settings );
+		var namespace = '.dt.DT_details';
+		var drawEvent = 'draw'+namespace;
+		var colvisEvent = 'column-visibility'+namespace;
+		var destroyEvent = 'destroy'+namespace;
+		var data = settings.aoData;
+	
+		api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
+	
+		if ( _pluck( data, '_details' ).length > 0 ) {
+			// On each draw, insert the required elements into the document
+			api.on( drawEvent, function ( e, ctx ) {
+				if ( settings !== ctx ) {
+					return;
+				}
+	
+				api.rows( {page:'current'} ).eq(0).each( function (idx) {
+					// Internal data grab
+					var row = data[ idx ];
+	
+					if ( row._detailsShow ) {
+						row._details.insertAfter( row.nTr );
+					}
+				} );
+			} );
+	
+			// Column visibility change - update the colspan
+			api.on( colvisEvent, function ( e, ctx, idx, vis ) {
+				if ( settings !== ctx ) {
+					return;
+				}
+	
+				// Update the colspan for the details rows (note, only if it already has
+				// a colspan)
+				var row, visible = _fnVisbleColumns( ctx );
+	
+				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
+					row = data[i];
+	
+					if ( row._details ) {
+						row._details.children('td[colspan]').attr('colspan', visible );
+					}
+				}
+			} );
+	
+			// Table destroyed - nuke any child rows
+			api.on( destroyEvent, function ( e, ctx ) {
+				if ( settings !== ctx ) {
+					return;
+				}
+	
+				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
+					if ( data[i]._details ) {
+						__details_remove( api, i );
+					}
+				}
+			} );
+		}
+	};
+	
+	// Strings for the method names to help minification
+	var _emp = '';
+	var _child_obj = _emp+'row().child';
+	var _child_mth = _child_obj+'()';
+	
+	// data can be:
+	//  tr
+	//  string
+	//  jQuery or array of any of the above
+	_api_register( _child_mth, function ( data, klass ) {
+		var ctx = this.context;
+	
+		if ( data === undefined ) {
+			// get
+			return ctx.length && this.length ?
+				ctx[0].aoData[ this[0] ]._details :
+				undefined;
+		}
+		else if ( data === true ) {
+			// show
+			this.child.show();
+		}
+		else if ( data === false ) {
+			// remove
+			__details_remove( this );
+		}
+		else if ( ctx.length && this.length ) {
+			// set
+			__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
+		}
+	
+		return this;
+	} );
+	
+	
+	_api_register( [
+		_child_obj+'.show()',
+		_child_mth+'.show()' // only when `child()` was called with parameters (without
+	], function ( show ) {   // it returns an object and this method is not executed)
+		__details_display( this, true );
+		return this;
+	} );
+	
+	
+	_api_register( [
+		_child_obj+'.hide()',
+		_child_mth+'.hide()' // only when `child()` was called with parameters (without
+	], function () {         // it returns an object and this method is not executed)
+		__details_display( this, false );
+		return this;
+	} );
+	
+	
+	_api_register( [
+		_child_obj+'.remove()',
+		_child_mth+'.remove()' // only when `child()` was called with parameters (without
+	], function () {           // it returns an object and this method is not executed)
+		__details_remove( this );
+		return this;
+	} );
+	
+	
+	_api_register( _child_obj+'.isShown()', function () {
+		var ctx = this.context;
+	
+		if ( ctx.length && this.length ) {
+			// _detailsShown as false or undefined will fall through to return false
+			return ctx[0].aoData[ this[0] ]._detailsShow || false;
+		}
+		return false;
+	} );
+	
+	
+	
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Columns
+	 *
+	 * {integer}           - column index (>=0 count from left, <0 count from right)
+	 * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
+	 * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
+	 * "{string}:name"     - column name
+	 * "{string}"          - jQuery selector on column header nodes
+	 *
+	 */
+	
+	// can be an array of these items, comma separated list, or an array of comma
+	// separated lists
+	
+	var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
+	
+	
+	// r1 and r2 are redundant - but it means that the parameters match for the
+	// iterator callback in columns().data()
+	var __columnData = function ( settings, column, r1, r2, rows ) {
+		var a = [];
+		for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
+			a.push( _fnGetCellData( settings, rows[row], column ) );
+		}
+		return a;
+	};
+	
+	
+	var __column_selector = function ( settings, selector, opts )
+	{
+		var
+			columns = settings.aoColumns,
+			names = _pluck( columns, 'sName' ),
+			nodes = _pluck( columns, 'nTh' );
+	
+		var run = function ( s ) {
+			var selInt = _intVal( s );
+	
+			// Selector - all
+			if ( s === '' ) {
+				return _range( columns.length );
+			}
+			
+			// Selector - index
+			if ( selInt !== null ) {
+				return [ selInt >= 0 ?
+					selInt : // Count from left
+					columns.length + selInt // Count from right (+ because its a negative value)
+				];
+			}
+			
+			// Selector = function
+			if ( typeof s === 'function' ) {
+				var rows = _selector_row_indexes( settings, opts );
+	
+				return $.map( columns, function (col, idx) {
+					return s(
+							idx,
+							__columnData( settings, idx, 0, 0, rows ),
+							nodes[ idx ]
+						) ? idx : null;
+				} );
+			}
+	
+			// jQuery or string selector
+			var match = typeof s === 'string' ?
+				s.match( __re_column_selector ) :
+				'';
+	
+			if ( match ) {
+				switch( match[2] ) {
+					case 'visIdx':
+					case 'visible':
+						var idx = parseInt( match[1], 10 );
+						// Visible index given, convert to column index
+						if ( idx < 0 ) {
+							// Counting from the right
+							var visColumns = $.map( columns, function (col,i) {
+								return col.bVisible ? i : null;
+							} );
+							return [ visColumns[ visColumns.length + idx ] ];
+						}
+						// Counting from the left
+						return [ _fnVisibleToColumnIndex( settings, idx ) ];
+	
+					case 'name':
+						// match by name. `names` is column index complete and in order
+						return $.map( names, function (name, i) {
+							return name === match[1] ? i : null;
+						} );
+				}
+			}
+			else {
+				// jQuery selector on the TH elements for the columns
+				return $( nodes )
+					.filter( s )
+					.map( function () {
+						return $.inArray( this, nodes ); // `nodes` is column index complete and in order
+					} )
+					.toArray();
+			}
+		};
+	
+		return _selector_run( 'column', selector, run, settings, opts );
+	};
+	
+	
+	var __setColumnVis = function ( settings, column, vis, recalc ) {
+		var
+			cols = settings.aoColumns,
+			col  = cols[ column ],
+			data = settings.aoData,
+			row, cells, i, ien, tr;
+	
+		// Get
+		if ( vis === undefined ) {
+			return col.bVisible;
+		}
+	
+		// Set
+		// No change
+		if ( col.bVisible === vis ) {
+			return;
+		}
+	
+		if ( vis ) {
+			// Insert column
+			// Need to decide if we should use appendChild or insertBefore
+			var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
+	
+			for ( i=0, ien=data.length ; i<ien ; i++ ) {
+				tr = data[i].nTr;
+				cells = data[i].anCells;
+	
+				if ( tr ) {
+					// insertBefore can act like appendChild if 2nd arg is null
+					tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
+				}
+			}
+		}
+		else {
+			// Remove column
+			$( _pluck( settings.aoData, 'anCells', column ) ).detach();
+		}
+	
+		// Common actions
+		col.bVisible = vis;
+		_fnDrawHead( settings, settings.aoHeader );
+		_fnDrawHead( settings, settings.aoFooter );
+	
+		if ( recalc === undefined || recalc ) {
+			// Automatically adjust column sizing
+			_fnAdjustColumnSizing( settings );
+	
+			// Realign columns for scrolling
+			if ( settings.oScroll.sX || settings.oScroll.sY ) {
+				_fnScrollDraw( settings );
+			}
+		}
+	
+		_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] );
+	
+		_fnSaveState( settings );
+	};
+	
+	
+	_api_register( 'columns()', function ( selector, opts ) {
+		// argument shifting
+		if ( selector === undefined ) {
+			selector = '';
+		}
+		else if ( $.isPlainObject( selector ) ) {
+			opts = selector;
+			selector = '';
+		}
+	
+		opts = _selector_opts( opts );
+	
+		var inst = this.iterator( 'table', function ( settings ) {
+			return __column_selector( settings, selector, opts );
+		}, 1 );
+	
+		// Want argument shifting here and in _row_selector?
+		inst.selector.cols = selector;
+		inst.selector.opts = opts;
+	
+		return inst;
+	} );
+	
+	_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
+		return this.iterator( 'column', function ( settings, column ) {
+			return settings.aoColumns[column].nTh;
+		}, 1 );
+	} );
+	
+	_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
+		return this.iterator( 'column', function ( settings, column ) {
+			return settings.aoColumns[column].nTf;
+		}, 1 );
+	} );
+	
+	_api_registerPlural( 'columns().data()', 'column().data()', function () {
+		return this.iterator( 'column-rows', __columnData, 1 );
+	} );
+	
+	_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
+		return this.iterator( 'column', function ( settings, column ) {
+			return settings.aoColumns[column].mData;
+		}, 1 );
+	} );
+	
+	_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
+		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
+			return _pluck_order( settings.aoData, rows,
+				type === 'search' ? '_aFilterData' : '_aSortData', column
+			);
+		}, 1 );
+	} );
+	
+	_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
+		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
+			return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
+		}, 1 );
+	} );
+	
+	_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
+		return this.iterator( 'column', function ( settings, column ) {
+			if ( vis === undefined ) {
+				return settings.aoColumns[ column ].bVisible;
+			} // else
+			__setColumnVis( settings, column, vis, calc );
+		} );
+	} );
+	
+	_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
+		return this.iterator( 'column', function ( settings, column ) {
+			return type === 'visible' ?
+				_fnColumnIndexToVisible( settings, column ) :
+				column;
+		}, 1 );
+	} );
+	
+	_api_register( 'columns.adjust()', function () {
+		return this.iterator( 'table', function ( settings ) {
+			_fnAdjustColumnSizing( settings );
+		}, 1 );
+	} );
+	
+	_api_register( 'column.index()', function ( type, idx ) {
+		if ( this.context.length !== 0 ) {
+			var ctx = this.context[0];
+	
+			if ( type === 'fromVisible' || type === 'toData' ) {
+				return _fnVisibleToColumnIndex( ctx, idx );
+			}
+			else if ( type === 'fromData' || type === 'toVisible' ) {
+				return _fnColumnIndexToVisible( ctx, idx );
+			}
+		}
+	} );
+	
+	_api_register( 'column()', function ( selector, opts ) {
+		return _selector_first( this.columns( selector, opts ) );
+	} );
+	
+	
+	
+	
+	var __cell_selector = function ( settings, selector, opts )
+	{
+		var data = settings.aoData;
+		var rows = _selector_row_indexes( settings, opts );
+		var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
+		var allCells = $( [].concat.apply([], cells) );
+		var row;
+		var columns = settings.aoColumns.length;
+		var a, i, ien, j, o, host;
+	
+		var run = function ( s ) {
+			var fnSelector = typeof s === 'function';
+	
+			if ( s === null || s === undefined || fnSelector ) {
+				// All cells and function selectors
+				a = [];
+	
+				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
+					row = rows[i];
+	
+					for ( j=0 ; j<columns ; j++ ) {
+						o = {
+							row: row,
+							column: j
+						};
+	
+						if ( fnSelector ) {
+							// Selector - function
+							host = settings.aoData[ row ];
+	
+							if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
+								a.push( o );
+							}
+						}
+						else {
+							// Selector - all
+							a.push( o );
+						}
+					}
+				}
+	
+				return a;
+			}
+			
+			// Selector - index
+			if ( $.isPlainObject( s ) ) {
+				return [s];
+			}
+	
+			// Selector - jQuery filtered cells
+			return allCells
+				.filter( s )
+				.map( function (i, el) {
+					row = el.parentNode._DT_RowIndex;
+	
+					return {
+						row: row,
+						column: $.inArray( el, data[ row ].anCells )
+					};
+				} )
+				.toArray();
+		};
+	
+		return _selector_run( 'cell', selector, run, settings, opts );
+	};
+	
+	
+	
+	
+	_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
+		// Argument shifting
+		if ( $.isPlainObject( rowSelector ) ) {
+			// Indexes
+			if ( rowSelector.row === undefined ) {
+				// Selector options in first parameter
+				opts = rowSelector;
+				rowSelector = null;
+			}
+			else {
+				// Cell index objects in first parameter
+				opts = columnSelector;
+				columnSelector = null;
+			}
+		}
+		if ( $.isPlainObject( columnSelector ) ) {
+			opts = columnSelector;
+			columnSelector = null;
+		}
+	
+		// Cell selector
+		if ( columnSelector === null || columnSelector === undefined ) {
+			return this.iterator( 'table', function ( settings ) {
+				return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
+			} );
+		}
+	
+		// Row + column selector
+		var columns = this.columns( columnSelector, opts );
+		var rows = this.rows( rowSelector, opts );
+		var a, i, ien, j, jen;
+	
+		var cells = this.iterator( 'table', function ( settings, idx ) {
+			a = [];
+	
+			for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
+				for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
+					a.push( {
+						row:    rows[idx][i],
+						column: columns[idx][j]
+					} );
+				}
+			}
+	
+			return a;
+		}, 1 );
+	
+		$.extend( cells.selector, {
+			cols: columnSelector,
+			rows: rowSelector,
+			opts: opts
+		} );
+	
+		return cells;
+	} );
+	
+	
+	_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
+		return this.iterator( 'cell', function ( settings, row, column ) {
+			var cells = settings.aoData[ row ].anCells;
+			return cells ?
+				cells[ column ] :
+				undefined;
+		}, 1 );
+	} );
+	
+	
+	_api_register( 'cells().data()', function () {
+		return this.iterator( 'cell', function ( settings, row, column ) {
+			return _fnGetCellData( settings, row, column );
+		}, 1 );
+	} );
+	
+	
+	_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
+		type = type === 'search' ? '_aFilterData' : '_aSortData';
+	
+		return this.iterator( 'cell', function ( settings, row, column ) {
+			return settings.aoData[ row ][ type ][ column ];
+		}, 1 );
+	} );
+	
+	
+	_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
+		return this.iterator( 'cell', function ( settings, row, column ) {
+			return _fnGetCellData( settings, row, column, type );
+		}, 1 );
+	} );
+	
+	
+	_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
+		return this.iterator( 'cell', function ( settings, row, column ) {
+			return {
+				row: row,
+				column: column,
+				columnVisible: _fnColumnIndexToVisible( settings, column )
+			};
+		}, 1 );
+	} );
+	
+	
+	_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
+		return this.iterator( 'cell', function ( settings, row, column ) {
+			_fnInvalidate( settings, row, src, column );
+		} );
+	} );
+	
+	
+	
+	_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
+		return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
+	} );
+	
+	
+	_api_register( 'cell().data()', function ( data ) {
+		var ctx = this.context;
+		var cell = this[0];
+	
+		if ( data === undefined ) {
+			// Get
+			return ctx.length && cell.length ?
+				_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
+				undefined;
+		}
+	
+		// Set
+		_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
+		_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
+	
+		return this;
+	} );
+	
+	
+	
+	/**
+	 * Get current ordering (sorting) that has been applied to the table.
+	 *
+	 * @returns {array} 2D array containing the sorting information for the first
+	 *   table in the current context. Each element in the parent array represents
+	 *   a column being sorted upon (i.e. multi-sorting with two columns would have
+	 *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
+	 *   the column index that the sorting condition applies to, the second is the
+	 *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
+	 *   index of the sorting order from the `column.sorting` initialisation array.
+	 *//**
+	 * Set the ordering for the table.
+	 *
+	 * @param {integer} order Column index to sort upon.
+	 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
+	 * @returns {DataTables.Api} this
+	 *//**
+	 * Set the ordering for the table.
+	 *
+	 * @param {array} order 1D array of sorting information to be applied.
+	 * @param {array} [...] Optional additional sorting conditions
+	 * @returns {DataTables.Api} this
+	 *//**
+	 * Set the ordering for the table.
+	 *
+	 * @param {array} order 2D array of sorting information to be applied.
+	 * @returns {DataTables.Api} this
+	 */
+	_api_register( 'order()', function ( order, dir ) {
+		var ctx = this.context;
+	
+		if ( order === undefined ) {
+			// get
+			return ctx.length !== 0 ?
+				ctx[0].aaSorting :
+				undefined;
+		}
+	
+		// set
+		if ( typeof order === 'number' ) {
+			// Simple column / direction passed in
+			order = [ [ order, dir ] ];
+		}
+		else if ( ! $.isArray( order[0] ) ) {
+			// Arguments passed in (list of 1D arrays)
+			order = Array.prototype.slice.call( arguments );
+		}
+		// otherwise a 2D array was passed in
+	
+		return this.iterator( 'table', function ( settings ) {
+			settings.aaSorting = order.slice();
+		} );
+	} );
+	
+	
+	/**
+	 * Attach a sort listener to an element for a given column
+	 *
+	 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
+	 *   listener to. This can take the form of a single DOM node, a jQuery
+	 *   collection of nodes or a jQuery selector which will identify the node(s).
+	 * @param {integer} column the column that a click on this node will sort on
+	 * @param {function} [callback] callback function when sort is run
+	 * @returns {DataTables.Api} this
+	 */
+	_api_register( 'order.listener()', function ( node, column, callback ) {
+		return this.iterator( 'table', function ( settings ) {
+			_fnSortAttachListener( settings, node, column, callback );
+		} );
+	} );
+	
+	
+	// Order by the selected column(s)
+	_api_register( [
+		'columns().order()',
+		'column().order()'
+	], function ( dir ) {
+		var that = this;
+	
+		return this.iterator( 'table', function ( settings, i ) {
+			var sort = [];
+	
+			$.each( that[i], function (j, col) {
+				sort.push( [ col, dir ] );
+			} );
+	
+			settings.aaSorting = sort;
+		} );
+	} );
+	
+	
+	
+	_api_register( 'search()', function ( input, regex, smart, caseInsen ) {
+		var ctx = this.context;
+	
+		if ( input === undefined ) {
+			// get
+			return ctx.length !== 0 ?
+				ctx[0].oPreviousSearch.sSearch :
+				undefined;
+		}
+	
+		// set
+		return this.iterator( 'table', function ( settings ) {
+			if ( ! settings.oFeatures.bFilter ) {
+				return;
+			}
+	
+			_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
+				"sSearch": input+"",
+				"bRegex":  regex === null ? false : regex,
+				"bSmart":  smart === null ? true  : smart,
+				"bCaseInsensitive": caseInsen === null ? true : caseInsen
+			} ), 1 );
+		} );
+	} );
+	
+	
+	_api_registerPlural(
+		'columns().search()',
+		'column().search()',
+		function ( input, regex, smart, caseInsen ) {
+			return this.iterator( 'column', function ( settings, column ) {
+				var preSearch = settings.aoPreSearchCols;
+	
+				if ( input === undefined ) {
+					// get
+					return preSearch[ column ].sSearch;
+				}
+	
+				// set
+				if ( ! settings.oFeatures.bFilter ) {
+					return;
+				}
+	
+				$.extend( preSearch[ column ], {
+					"sSearch": input+"",
+					"bRegex":  regex === null ? false : regex,
+					"bSmart":  smart === null ? true  : smart,
+					"bCaseInsensitive": caseInsen === null ? true : caseInsen
+				} );
+	
+				_fnFilterComplete( settings, settings.oPreviousSearch, 1 );
+			} );
+		}
+	);
+	
+	/*
+	 * State API methods
+	 */
+	
+	_api_register( 'state()', function () {
+		return this.context.length ?
+			this.context[0].oSavedState :
+			null;
+	} );
+	
+	
+	_api_register( 'state.clear()', function () {
+		return this.iterator( 'table', function ( settings ) {
+			// Save an empty object
+			settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
+		} );
+	} );
+	
+	
+	_api_register( 'state.loaded()', function () {
+		return this.context.length ?
+			this.context[0].oLoadedState :
+			null;
+	} );
+	
+	
+	_api_register( 'state.save()', function () {
+		return this.iterator( 'table', function ( settings ) {
+			_fnSaveState( settings );
+		} );
+	} );
+	
+	
+	
+	/**
+	 * Provide a common method for plug-ins to check the version of DataTables being
+	 * used, in order to ensure compatibility.
+	 *
+	 *  @param {string} version Version string to check for, in the format "X.Y.Z".
+	 *    Note that the formats "X" and "X.Y" are also acceptable.
+	 *  @returns {boolean} true if this version of DataTables is greater or equal to
+	 *    the required version, or false if this version of DataTales is not
+	 *    suitable
+	 *  @static
+	 *  @dtopt API-Static
+	 *
+	 *  @example
+	 *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
+	 */
+	DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
+	{
+		var aThis = DataTable.version.split('.');
+		var aThat = version.split('.');
+		var iThis, iThat;
+	
+		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
+			iThis = parseInt( aThis[i], 10 ) || 0;
+			iThat = parseInt( aThat[i], 10 ) || 0;
+	
+			// Parts are the same, keep comparing
+			if (iThis === iThat) {
+				continue;
+			}
+	
+			// Parts are different, return immediately
+			return iThis > iThat;
+		}
+	
+		return true;
+	};
+	
+	
+	/**
+	 * Check if a `<table>` node is a DataTable table already or not.
+	 *
+	 *  @param {node|jquery|string} table Table node, jQuery object or jQuery
+	 *      selector for the table to test. Note that if more than more than one
+	 *      table is passed on, only the first will be checked
+	 *  @returns {boolean} true the table given is a DataTable, or false otherwise
+	 *  @static
+	 *  @dtopt API-Static
+	 *
+	 *  @example
+	 *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
+	 *      $('#example').dataTable();
+	 *    }
+	 */
+	DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
+	{
+		var t = $(table).get(0);
+		var is = false;
+	
+		$.each( DataTable.settings, function (i, o) {
+			var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
+			var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
+	
+			if ( o.nTable === t || head === t || foot === t ) {
+				is = true;
+			}
+		} );
+	
+		return is;
+	};
+	
+	
+	/**
+	 * Get all DataTable tables that have been initialised - optionally you can
+	 * select to get only currently visible tables.
+	 *
+	 *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
+	 *    or visible tables only.
+	 *  @returns {array} Array of `table` nodes (not DataTable instances) which are
+	 *    DataTables
+	 *  @static
+	 *  @dtopt API-Static
+	 *
+	 *  @example
+	 *    $.each( $.fn.dataTable.tables(true), function () {
+	 *      $(table).DataTable().columns.adjust();
+	 *    } );
+	 */
+	DataTable.tables = DataTable.fnTables = function ( visible )
+	{
+		return $.map( DataTable.settings, function (o) {
+			if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
+				return o.nTable;
+			}
+		} );
+	};
+	
+	
+	/**
+	 * DataTables utility methods
+	 * 
+	 * This namespace provides helper methods that DataTables uses internally to
+	 * create a DataTable, but which are not exclusively used only for DataTables.
+	 * These methods can be used by extension authors to save the duplication of
+	 * code.
+	 *
+	 *  @namespace
+	 */
+	DataTable.util = {
+		/**
+		 * Throttle the calls to a function. Arguments and context are maintained
+		 * for the throttled function.
+		 *
+		 * @param {function} fn Function to be called
+		 * @param {integer} freq Call frequency in mS
+		 * @return {function} Wrapped function
+		 */
+		throttle: _fnThrottle,
+	
+	
+		/**
+		 * Escape a string such that it can be used in a regular expression
+		 *
+		 *  @param {string} sVal string to escape
+		 *  @returns {string} escaped string
+		 */
+		escapeRegex: _fnEscapeRegex
+	};
+	
+	
+	/**
+	 * Convert from camel case parameters to Hungarian notation. This is made public
+	 * for the extensions to provide the same ability as DataTables core to accept
+	 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
+	 * parameters.
+	 *
+	 *  @param {object} src The model object which holds all parameters that can be
+	 *    mapped.
+	 *  @param {object} user The object to convert from camel case to Hungarian.
+	 *  @param {boolean} force When set to `true`, properties which already have a
+	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
+	 *    won't be.
+	 */
+	DataTable.camelToHungarian = _fnCamelToHungarian;
+	
+	
+	
+	/**
+	 *
+	 */
+	_api_register( '$()', function ( selector, opts ) {
+		var
+			rows   = this.rows( opts ).nodes(), // Get all rows
+			jqRows = $(rows);
+	
+		return $( [].concat(
+			jqRows.filter( selector ).toArray(),
+			jqRows.find( selector ).toArray()
+		) );
+	} );
+	
+	
+	// jQuery functions to operate on the tables
+	$.each( [ 'on', 'one', 'off' ], function (i, key) {
+		_api_register( key+'()', function ( /* event, handler */ ) {
+			var args = Array.prototype.slice.call(arguments);
+	
+			// Add the `dt` namespace automatically if it isn't already present
+			if ( ! args[0].match(/\.dt\b/) ) {
+				args[0] += '.dt';
+			}
+	
+			var inst = $( this.tables().nodes() );
+			inst[key].apply( inst, args );
+			return this;
+		} );
+	} );
+	
+	
+	_api_register( 'clear()', function () {
+		return this.iterator( 'table', function ( settings ) {
+			_fnClearTable( settings );
+		} );
+	} );
+	
+	
+	_api_register( 'settings()', function () {
+		return new _Api( this.context, this.context );
+	} );
+	
+	
+	_api_register( 'init()', function () {
+		var ctx = this.context;
+		return ctx.length ? ctx[0].oInit : null;
+	} );
+	
+	
+	_api_register( 'data()', function () {
+		return this.iterator( 'table', function ( settings ) {
+			return _pluck( settings.aoData, '_aData' );
+		} ).flatten();
+	} );
+	
+	
+	_api_register( 'destroy()', function ( remove ) {
+		remove = remove || false;
+	
+		return this.iterator( 'table', function ( settings ) {
+			var orig      = settings.nTableWrapper.parentNode;
+			var classes   = settings.oClasses;
+			var table     = settings.nTable;
+			var tbody     = settings.nTBody;
+			var thead     = settings.nTHead;
+			var tfoot     = settings.nTFoot;
+			var jqTable   = $(table);
+			var jqTbody   = $(tbody);
+			var jqWrapper = $(settings.nTableWrapper);
+			var rows      = $.map( settings.aoData, function (r) { return r.nTr; } );
+			var i, ien;
+	
+			// Flag to note that the table is currently being destroyed - no action
+			// should be taken
+			settings.bDestroying = true;
+	
+			// Fire off the destroy callbacks for plug-ins etc
+			_fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
+	
+			// If not being removed from the document, make all columns visible
+			if ( ! remove ) {
+				new _Api( settings ).columns().visible( true );
+			}
+	
+			// Blitz all `DT` namespaced events (these are internal events, the
+			// lowercase, `dt` events are user subscribed and they are responsible
+			// for removing them
+			jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
+			$(window).unbind('.DT-'+settings.sInstance);
+	
+			// When scrolling we had to break the table up - restore it
+			if ( table != thead.parentNode ) {
+				jqTable.children('thead').detach();
+				jqTable.append( thead );
+			}
+	
+			if ( tfoot && table != tfoot.parentNode ) {
+				jqTable.children('tfoot').detach();
+				jqTable.append( tfoot );
+			}
+	
+			// Remove the DataTables generated nodes, events and classes
+			jqTable.detach();
+			jqWrapper.detach();
+	
+			settings.aaSorting = [];
+			settings.aaSortingFixed = [];
+			_fnSortingClasses( settings );
+	
+			$( rows ).removeClass( settings.asStripeClasses.join(' ') );
+	
+			$('th, td', thead).removeClass( classes.sSortable+' '+
+				classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
+			);
+	
+			if ( settings.bJUI ) {
+				$('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();
+				$('th, td', thead).each( function () {
+					var wrapper = $('div.'+classes.sSortJUIWrapper, this);
+					$(this).append( wrapper.contents() );
+					wrapper.detach();
+				} );
+			}
+	
+			if ( ! remove && orig ) {
+				// insertBefore acts like appendChild if !arg[1]
+				orig.insertBefore( table, settings.nTableReinsertBefore );
+			}
+	
+			// Add the TR elements back into the table in their original order
+			jqTbody.children().detach();
+			jqTbody.append( rows );
+	
+			// Restore the width of the original table - was read from the style property,
+			// so we can restore directly to that
+			jqTable
+				.css( 'width', settings.sDestroyWidth )
+				.removeClass( classes.sTable );
+	
+			// If the were originally stripe classes - then we add them back here.
+			// Note this is not fool proof (for example if not all rows had stripe
+			// classes - but it's a good effort without getting carried away
+			ien = settings.asDestroyStripes.length;
+	
+			if ( ien ) {
+				jqTbody.children().each( function (i) {
+					$(this).addClass( settings.asDestroyStripes[i % ien] );
+				} );
+			}
+	
+			/* Remove the settings object from the settings array */
+			var idx = $.inArray( settings, DataTable.settings );
+			if ( idx !== -1 ) {
+				DataTable.settings.splice( idx, 1 );
+			}
+		} );
+	} );
+	
+	
+	// Add the `every()` method for rows, columns and cells in a compact form
+	$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
+		_api_register( type+'s().every()', function ( fn ) {
+			return this.iterator( type, function ( settings, idx, idx2 ) {
+				// idx2 is undefined for rows and columns.
+				fn.call( new _Api( settings )[ type ]( idx, idx2 ) );
+			} );
+		} );
+	} );
+	
+	
+	// i18n method for extensions to be able to use the language object from the
+	// DataTable
+	_api_register( 'i18n()', function ( token, def, plural ) {
+		var ctx = this.context[0];
+		var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
+	
+		if ( resolved === undefined ) {
+			resolved = def;
+		}
+	
+		if ( plural !== undefined && $.isPlainObject( resolved ) ) {
+			resolved = resolved[ plural ] !== undefined ?
+				resolved[ plural ] :
+				resolved._;
+		}
+	
+		return resolved.replace( '%d', plural ); // nb: plural might be undefined,
+	} );
+
+	/**
+	 * Version string for plug-ins to check compatibility. Allowed format is
+	 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
+	 * only for non-release builds. See http://semver.org/ for more information.
+	 *  @member
+	 *  @type string
+	 *  @default Version number
+	 */
+	DataTable.version = "1.10.7";
+
+	/**
+	 * Private data store, containing all of the settings objects that are
+	 * created for the tables on a given page.
+	 *
+	 * Note that the `DataTable.settings` object is aliased to
+	 * `jQuery.fn.dataTableExt` through which it may be accessed and
+	 * manipulated, or `jQuery.fn.dataTable.settings`.
+	 *  @member
+	 *  @type array
+	 *  @default []
+	 *  @private
+	 */
+	DataTable.settings = [];
+
+	/**
+	 * Object models container, for the various models that DataTables has
+	 * available to it. These models define the objects that are used to hold
+	 * the active state and configuration of the table.
+	 *  @namespace
+	 */
+	DataTable.models = {};
+	
+	
+	
+	/**
+	 * Template object for the way in which DataTables holds information about
+	 * search information for the global filter and individual column filters.
+	 *  @namespace
+	 */
+	DataTable.models.oSearch = {
+		/**
+		 * Flag to indicate if the filtering should be case insensitive or not
+		 *  @type boolean
+		 *  @default true
+		 */
+		"bCaseInsensitive": true,
+	
+		/**
+		 * Applied search term
+		 *  @type string
+		 *  @default <i>Empty string</i>
+		 */
+		"sSearch": "",
+	
+		/**
+		 * Flag to indicate if the search term should be interpreted as a
+		 * regular expression (true) or not (false) and therefore and special
+		 * regex characters escaped.
+		 *  @type boolean
+		 *  @default false
+		 */
+		"bRegex": false,
+	
+		/**
+		 * Flag to indicate if DataTables is to use its smart filtering or not.
+		 *  @type boolean
+		 *  @default true
+		 */
+		"bSmart": true
+	};
+	
+	
+	
+	
+	/**
+	 * Template object for the way in which DataTables holds information about
+	 * each individual row. This is the object format used for the settings
+	 * aoData array.
+	 *  @namespace
+	 */
+	DataTable.models.oRow = {
+		/**
+		 * TR element for the row
+		 *  @type node
+		 *  @default null
+		 */
+		"nTr": null,
+	
+		/**
+		 * Array of TD elements for each row. This is null until the row has been
+		 * created.
+		 *  @type array nodes
+		 *  @default []
+		 */
+		"anCells": null,
+	
+		/**
+		 * Data object from the original data source for the row. This is either
+		 * an array if using the traditional form of DataTables, or an object if
+		 * using mData options. The exact type will depend on the passed in
+		 * data from the data source, or will be an array if using DOM a data
+		 * source.
+		 *  @type array|object
+		 *  @default []
+		 */
+		"_aData": [],
+	
+		/**
+		 * Sorting data cache - this array is ostensibly the same length as the
+		 * number of columns (although each index is generated only as it is
+		 * needed), and holds the data that is used for sorting each column in the
+		 * row. We do this cache generation at the start of the sort in order that
+		 * the formatting of the sort data need be done only once for each cell
+		 * per sort. This array should not be read from or written to by anything
+		 * other than the master sorting methods.
+		 *  @type array
+		 *  @default null
+		 *  @private
+		 */
+		"_aSortData": null,
+	
+		/**
+		 * Per cell filtering data cache. As per the sort data cache, used to
+		 * increase the performance of the filtering in DataTables
+		 *  @type array
+		 *  @default null
+		 *  @private
+		 */
+		"_aFilterData": null,
+	
+		/**
+		 * Filtering data cache. This is the same as the cell filtering cache, but
+		 * in this case a string rather than an array. This is easily computed with
+		 * a join on `_aFilterData`, but is provided as a cache so the join isn't
+		 * needed on every search (memory traded for performance)
+		 *  @type array
+		 *  @default null
+		 *  @private
+		 */
+		"_sFilterRow": null,
+	
+		/**
+		 * Cache of the class name that DataTables has applied to the row, so we
+		 * can quickly look at this variable rather than needing to do a DOM check
+		 * on className for the nTr property.
+		 *  @type string
+		 *  @default <i>Empty string</i>
+		 *  @private
+		 */
+		"_sRowStripe": "",
+	
+		/**
+		 * Denote if the original data source was from the DOM, or the data source
+		 * object. This is used for invalidating data, so DataTables can
+		 * automatically read data from the original source, unless uninstructed
+		 * otherwise.
+		 *  @type string
+		 *  @default null
+		 *  @private
+		 */
+		"src": null
+	};
+	
+	
+	/**
+	 * Template object for the column information object in DataTables. This object
+	 * is held in the settings aoColumns array and contains all the information that
+	 * DataTables needs about each individual column.
+	 *
+	 * Note that this object is related to {@link DataTable.defaults.column}
+	 * but this one is the internal data store for DataTables's cache of columns.
+	 * It should NOT be manipulated outside of DataTables. Any configuration should
+	 * be done through the initialisation options.
+	 *  @namespace
+	 */
+	DataTable.models.oColumn = {
+		/**
+		 * Column index. This could be worked out on-the-fly with $.inArray, but it
+		 * is faster to just hold it as a variable
+		 *  @type integer
+		 *  @default null
+		 */
+		"idx": null,
+	
+		/**
+		 * A list of the columns that sorting should occur on when this column
+		 * is sorted. That this property is an array allows multi-column sorting
+		 * to be defined for a column (for example first name / last name columns
+		 * would benefit from this). The values are integers pointing to the
+		 * columns to be sorted on (typically it will be a single integer pointing
+		 * at itself, but that doesn't need to be the case).
+		 *  @type array
+		 */
+		"aDataSort": null,
+	
+		/**
+		 * Define the sorting directions that are applied to the column, in sequence
+		 * as the column is repeatedly sorted upon - i.e. the first value is used
+		 * as the sorting direction when the column if first sorted (clicked on).
+		 * Sort it again (click again) and it will move on to the next index.
+		 * Repeat until loop.
+		 *  @type array
+		 */
+		"asSorting": null,
+	
+		/**
+		 * Flag to indicate if the column is searchable, and thus should be included
+		 * in the filtering or not.
+		 *  @type boolean
+		 */
+		"bSearchable": null,
+	
+		/**
+		 * Flag to indicate if the column is sortable or not.
+		 *  @type boolean
+		 */
+		"bSortable": null,
+	
+		/**
+		 * Flag to indicate if the column is currently visible in the table or not
+		 *  @type boolean
+		 */
+		"bVisible": null,
+	
+		/**
+		 * Store for manual type assignment using the `column.type` option. This
+		 * is held in store so we can manipulate the column's `sType` property.
+		 *  @type string
+		 *  @default null
+		 *  @private
+		 */
+		"_sManualType": null,
+	
+		/**
+		 * Flag to indicate if HTML5 data attributes should be used as the data
+		 * source for filtering or sorting. True is either are.
+		 *  @type boolean
+		 *  @default false
+		 *  @private
+		 */
+		"_bAttrSrc": false,
+	
+		/**
+		 * Developer definable function that is called whenever a cell is created (Ajax source,
+		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
+		 * allowing you to modify the DOM element (add background colour for example) when the
+		 * element is available.
+		 *  @type function
+		 *  @param {element} nTd The TD node that has been created
+		 *  @param {*} sData The Data for the cell
+		 *  @param {array|object} oData The data for the whole row
+		 *  @param {int} iRow The row index for the aoData data store
+		 *  @default null
+		 */
+		"fnCreatedCell": null,
+	
+		/**
+		 * Function to get data from a cell in a column. You should <b>never</b>
+		 * access data directly through _aData internally in DataTables - always use
+		 * the method attached to this property. It allows mData to function as
+		 * required. This function is automatically assigned by the column
+		 * initialisation method
+		 *  @type function
+		 *  @param {array|object} oData The data array/object for the array
+		 *    (i.e. aoData[]._aData)
+		 *  @param {string} sSpecific The specific data type you want to get -
+		 *    'display', 'type' 'filter' 'sort'
+		 *  @returns {*} The data for the cell from the given row's data
+		 *  @default null
+		 */
+		"fnGetData": null,
+	
+		/**
+		 * Function to set data for a cell in the column. You should <b>never</b>
+		 * set the data directly to _aData internally in DataTables - always use
+		 * this method. It allows mData to function as required. This function
+		 * is automatically assigned by the column initialisation method
+		 *  @type function
+		 *  @param {array|object} oData The data array/object for the array
+		 *    (i.e. aoData[]._aData)
+		 *  @param {*} sValue Value to set
+		 *  @default null
+		 */
+		"fnSetData": null,
+	
+		/**
+		 * Property to read the value for the cells in the column from the data
+		 * source array / object. If null, then the default content is used, if a
+		 * function is given then the return from the function is used.
+		 *  @type function|int|string|null
+		 *  @default null
+		 */
+		"mData": null,
+	
+		/**
+		 * Partner property to mData which is used (only when defined) to get
+		 * the data - i.e. it is basically the same as mData, but without the
+		 * 'set' option, and also the data fed to it is the result from mData.
+		 * This is the rendering method to match the data method of mData.
+		 *  @type function|int|string|null
+		 *  @default null
+		 */
+		"mRender": null,
+	
+		/**
+		 * Unique header TH/TD element for this column - this is what the sorting
+		 * listener is attached to (if sorting is enabled.)
+		 *  @type node
+		 *  @default null
+		 */
+		"nTh": null,
+	
+		/**
+		 * Unique footer TH/TD element for this column (if there is one). Not used
+		 * in DataTables as such, but can be used for plug-ins to reference the
+		 * footer for each column.
+		 *  @type node
+		 *  @default null
+		 */
+		"nTf": null,
+	
+		/**
+		 * The class to apply to all TD elements in the table's TBODY for the column
+		 *  @type string
+		 *  @default null
+		 */
+		"sClass": null,
+	
+		/**
+		 * When DataTables calculates the column widths to assign to each column,
+		 * it finds the longest string in each column and then constructs a
+		 * temporary table and reads the widths from that. The problem with this
+		 * is that "mmm" is much wider then "iiii", but the latter is a longer
+		 * string - thus the calculation can go wrong (doing it properly and putting
+		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
+		 * a "work around" we provide this option. It will append its value to the
+		 * text that is found to be the longest string for the column - i.e. padding.
+		 *  @type string
+		 */
+		"sContentPadding": null,
+	
+		/**
+		 * Allows a default value to be given for a column's data, and will be used
+		 * whenever a null data source is encountered (this can be because mData
+		 * is set to null, or because the data source itself is null).
+		 *  @type string
+		 *  @default null
+		 */
+		"sDefaultContent": null,
+	
+		/**
+		 * Name for the column, allowing reference to the column by name as well as
+		 * by index (needs a lookup to work by name).
+		 *  @type string
+		 */
+		"sName": null,
+	
+		/**
+		 * Custom sorting data type - defines which of the available plug-ins in
+		 * afnSortData the custom sorting will use - if any is defined.
+		 *  @type string
+		 *  @default std
+		 */
+		"sSortDataType": 'std',
+	
+		/**
+		 * Class to be applied to the header element when sorting on this column
+		 *  @type string
+		 *  @default null
+		 */
+		"sSortingClass": null,
+	
+		/**
+		 * Class to be applied to the header element when sorting on this column -
+		 * when jQuery UI theming is used.
+		 *  @type string
+		 *  @default null
+		 */
+		"sSortingClassJUI": null,
+	
+		/**
+		 * Title of the column - what is seen in the TH element (nTh).
+		 *  @type string
+		 */
+		"sTitle": null,
+	
+		/**
+		 * Column sorting and filtering type
+		 *  @type string
+		 *  @default null
+		 */
+		"sType": null,
+	
+		/**
+		 * Width of the column
+		 *  @type string
+		 *  @default null
+		 */
+		"sWidth": null,
+	
+		/**
+		 * Width of the column when it was first "encountered"
+		 *  @type string
+		 *  @default null
+		 */
+		"sWidthOrig": null
+	};
+	
+	
+	/*
+	 * Developer note: The properties of the object below are given in Hungarian
+	 * notation, that was used as the interface for DataTables prior to v1.10, however
+	 * from v1.10 onwards the primary interface is camel case. In order to avoid
+	 * breaking backwards compatibility utterly with this change, the Hungarian
+	 * version is still, internally the primary interface, but is is not documented
+	 * - hence the @name tags in each doc comment. This allows a Javascript function
+	 * to create a map from Hungarian notation to camel case (going the other direction
+	 * would require each property to be listed, which would at around 3K to the size
+	 * of DataTables, while this method is about a 0.5K hit.
+	 *
+	 * Ultimately this does pave the way for Hungarian notation to be dropped
+	 * completely, but that is a massive amount of work and will break current
+	 * installs (therefore is on-hold until v2).
+	 */
+	
+	/**
+	 * Initialisation options that can be given to DataTables at initialisation
+	 * time.
+	 *  @namespace
+	 */
+	DataTable.defaults = {
+		/**
+		 * An array of data to use for the table, passed in at initialisation which
+		 * will be used in preference to any data which is already in the DOM. This is
+		 * particularly useful for constructing tables purely in Javascript, for
+		 * example with a custom Ajax call.
+		 *  @type array
+		 *  @default null
+		 *
+		 *  @dtopt Option
+		 *  @name DataTable.defaults.data
+		 *
+		 *  @example
+		 *    // Using a 2D array data source
+		 *    $(document).ready( function () {
+		 *      $('#example').dataTable( {
+		 *        "data": [
+		 *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
+		 *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
+		 *        ],
+		 *        "columns": [
+		 *          { "title": "Engine" },
+		 *          { "title": "Browser" },
+		 *          { "title": "Platform" },
+		 *          { "title": "Version" },
+		 *          { "title": "Grade" }
+		 *        ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using an array of objects as a data source (`data`)
+		 *    $(document).ready( function () {
+		 *      $('#example').dataTable( {
+		 *        "data": [
+		 *          {
+		 *            "engine":   "Trident",
+		 *            "browser":  "Internet Explorer 4.0",
+		 *            "platform": "Win 95+",
+		 *            "version":  4,
+		 *            "grade":    "X"
+		 *          },
+		 *          {
+		 *            "engine":   "Trident",
+		 *            "browser":  "Internet Explorer 5.0",
+		 *            "platform": "Win 95+",
+		 *            "version":  5,
+		 *            "grade":    "C"
+		 *          }
+		 *        ],
+		 *        "columns": [
+		 *          { "title": "Engine",   "data": "engine" },
+		 *          { "title": "Browser",  "data": "browser" },
+		 *          { "title": "Platform", "data": "platform" },
+		 *          { "title": "Version",  "data": "version" },
+		 *          { "title": "Grade",    "data": "grade" }
+		 *        ]
+		 *      } );
+		 *    } );
+		 */
+		"aaData": null,
+	
+	
+		/**
+		 * If ordering is enabled, then DataTables will perform a first pass sort on
+		 * initialisation. You can define which column(s) the sort is performed
+		 * upon, and the sorting direction, with this variable. The `sorting` array
+		 * should contain an array for each column to be sorted initially containing
+		 * the column's index and a direction string ('asc' or 'desc').
+		 *  @type array
+		 *  @default [[0,'asc']]
+		 *
+		 *  @dtopt Option
+		 *  @name DataTable.defaults.order
+		 *
+		 *  @example
+		 *    // Sort by 3rd column first, and then 4th column
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "order": [[2,'asc'], [3,'desc']]
+		 *      } );
+		 *    } );
+		 *
+		 *    // No initial sorting
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "order": []
+		 *      } );
+		 *    } );
+		 */
+		"aaSorting": [[0,'asc']],
+	
+	
+		/**
+		 * This parameter is basically identical to the `sorting` parameter, but
+		 * cannot be overridden by user interaction with the table. What this means
+		 * is that you could have a column (visible or hidden) which the sorting
+		 * will always be forced on first - any sorting after that (from the user)
+		 * will then be performed as required. This can be useful for grouping rows
+		 * together.
+		 *  @type array
+		 *  @default null
+		 *
+		 *  @dtopt Option
+		 *  @name DataTable.defaults.orderFixed
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "orderFixed": [[0,'asc']]
+		 *      } );
+		 *    } )
+		 */
+		"aaSortingFixed": [],
+	
+	
+		/**
+		 * DataTables can be instructed to load data to display in the table from a
+		 * Ajax source. This option defines how that Ajax call is made and where to.
+		 *
+		 * The `ajax` property has three different modes of operation, depending on
+		 * how it is defined. These are:
+		 *
+		 * * `string` - Set the URL from where the data should be loaded from.
+		 * * `object` - Define properties for `jQuery.ajax`.
+		 * * `function` - Custom data get function
+		 *
+		 * `string`
+		 * --------
+		 *
+		 * As a string, the `ajax` property simply defines the URL from which
+		 * DataTables will load data.
+		 *
+		 * `object`
+		 * --------
+		 *
+		 * As an object, the parameters in the object are passed to
+		 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
+		 * of the Ajax request. DataTables has a number of default parameters which
+		 * you can override using this option. Please refer to the jQuery
+		 * documentation for a full description of the options available, although
+		 * the following parameters provide additional options in DataTables or
+		 * require special consideration:
+		 *
+		 * * `data` - As with jQuery, `data` can be provided as an object, but it
+		 *   can also be used as a function to manipulate the data DataTables sends
+		 *   to the server. The function takes a single parameter, an object of
+		 *   parameters with the values that DataTables has readied for sending. An
+		 *   object may be returned which will be merged into the DataTables
+		 *   defaults, or you can add the items to the object that was passed in and
+		 *   not return anything from the function. This supersedes `fnServerParams`
+		 *   from DataTables 1.9-.
+		 *
+		 * * `dataSrc` - By default DataTables will look for the property `data` (or
+		 *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
+		 *   from an Ajax source or for server-side processing - this parameter
+		 *   allows that property to be changed. You can use Javascript dotted
+		 *   object notation to get a data source for multiple levels of nesting, or
+		 *   it my be used as a function. As a function it takes a single parameter,
+		 *   the JSON returned from the server, which can be manipulated as
+		 *   required, with the returned value being that used by DataTables as the
+		 *   data source for the table. This supersedes `sAjaxDataProp` from
+		 *   DataTables 1.9-.
+		 *
+		 * * `success` - Should not be overridden it is used internally in
+		 *   DataTables. To manipulate / transform the data returned by the server
+		 *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
+		 *
+		 * `function`
+		 * ----------
+		 *
+		 * As a function, making the Ajax call is left up to yourself allowing
+		 * complete control of the Ajax request. Indeed, if desired, a method other
+		 * than Ajax could be used to obtain the required data, such as Web storage
+		 * or an AIR database.
+		 *
+		 * The function is given four parameters and no return is required. The
+		 * parameters are:
+		 *
+		 * 1. _object_ - Data to send to the server
+		 * 2. _function_ - Callback function that must be executed when the required
+		 *    data has been obtained. That data should be passed into the callback
+		 *    as the only parameter
+		 * 3. _object_ - DataTables settings object for the table
+		 *
+		 * Note that this supersedes `fnServerData` from DataTables 1.9-.
+		 *
+		 *  @type string|object|function
+		 *  @default null
+		 *
+		 *  @dtopt Option
+		 *  @name DataTable.defaults.ajax
+		 *  @since 1.10.0
+		 *
+		 * @example
+		 *   // Get JSON data from a file via Ajax.
+		 *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
+		 *   $('#example').dataTable( {
+		 *     "ajax": "data.json"
+		 *   } );
+		 *
+		 * @example
+		 *   // Get JSON data from a file via Ajax, using `dataSrc` to change
+		 *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
+		 *   $('#example').dataTable( {
+		 *     "ajax": {
+		 *       "url": "data.json",
+		 *       "dataSrc": "tableData"
+		 *     }
+		 *   } );
+		 *
+		 * @example
+		 *   // Get JSON data from a file via Ajax, using `dataSrc` to read data
+		 *   // from a plain array rather than an array in an object
+		 *   $('#example').dataTable( {
+		 *     "ajax": {
+		 *       "url": "data.json",
+		 *       "dataSrc": ""
+		 *     }
+		 *   } );
+		 *
+		 * @example
+		 *   // Manipulate the data returned from the server - add a link to data
+		 *   // (note this can, should, be done using `render` for the column - this
+		 *   // is just a simple example of how the data can be manipulated).
+		 *   $('#example').dataTable( {
+		 *     "ajax": {
+		 *       "url": "data.json",
+		 *       "dataSrc": function ( json ) {
+		 *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {
+		 *           json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
+		 *         }
+		 *         return json;
+		 *       }
+		 *     }
+		 *   } );
+		 *
+		 * @example
+		 *   // Add data to the request
+		 *   $('#example').dataTable( {
+		 *     "ajax": {
+		 *       "url": "data.json",
+		 *       "data": function ( d ) {
+		 *         return {
+		 *           "extra_search": $('#extra').val()
+		 *         };
+		 *       }
+		 *     }
+		 *   } );
+		 *
+		 * @example
+		 *   // Send request as POST
+		 *   $('#example').dataTable( {
+		 *     "ajax": {
+		 *       "url": "data.json",
+		 *       "type": "POST"
+		 *     }
+		 *   } );
+		 *
+		 * @example
+		 *   // Get the data from localStorage (could interface with a form for
+		 *   // adding, editing and removing rows).
+		 *   $('#example').dataTable( {
+		 *     "ajax": function (data, callback, settings) {
+		 *       callback(
+		 *         JSON.parse( localStorage.getItem('dataTablesData') )
+		 *       );
+		 *     }
+		 *   } );
+		 */
+		"ajax": null,
+	
+	
+		/**
+		 * This parameter allows you to readily specify the entries in the length drop
+		 * down menu that DataTables shows when pagination is enabled. It can be
+		 * either a 1D array of options which will be used for both the displayed
+		 * option and the value, or a 2D array which will use the array in the first
+		 * position as the value, and the array in the second position as the
+		 * displayed options (useful for language strings such as 'All').
+		 *
+		 * Note that the `pageLength` property will be automatically set to the
+		 * first value given in this array, unless `pageLength` is also provided.
+		 *  @type array
+		 *  @default [ 10, 25, 50, 100 ]
+		 *
+		 *  @dtopt Option
+		 *  @name DataTable.defaults.lengthMenu
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
+		 *      } );
+		 *    } );
+		 */
+		"aLengthMenu": [ 10, 25, 50, 100 ],
+	
+	
+		/**
+		 * The `columns` option in the initialisation parameter allows you to define
+		 * details about the way individual columns behave. For a full list of
+		 * column options that can be set, please see
+		 * {@link DataTable.defaults.column}. Note that if you use `columns` to
+		 * define your columns, you must have an entry in the array for every single
+		 * column that you have in your table (these can be null if you don't which
+		 * to specify any options).
+		 *  @member
+		 *
+		 *  @name DataTable.defaults.column
+		 */
+		"aoColumns": null,
+	
+		/**
+		 * Very similar to `columns`, `columnDefs` allows you to target a specific
+		 * column, multiple columns, or all columns, using the `targets` property of
+		 * each object in the array. This allows great flexibility when creating
+		 * tables, as the `columnDefs` arrays can be of any length, targeting the
+		 * columns you specifically want. `columnDefs` may use any of the column
+		 * options available: {@link DataTable.defaults.column}, but it _must_
+		 * have `targets` defined in each object in the array. Values in the `targets`
+		 * array may be:
+		 *   <ul>
+		 *     <li>a string - class name will be matched on the TH for the column</li>
+		 *     <li>0 or a positive integer - column index counting from the left</li>
+		 *     <li>a negative integer - column index counting from the right</li>
+		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
+		 *   </ul>
+		 *  @member
+		 *
+		 *  @name DataTable.defaults.columnDefs
+		 */
+		"aoColumnDefs": null,
+	
+	
+		/**
+		 * Basically the same as `search`, this parameter defines the individual column
+		 * filtering state at initialisation time. The array must be of the same size
+		 * as the number of columns, and each element be an object with the parameters
+		 * `search` and `escapeRegex` (the latter is optional). 'null' is also
+		 * accepted and the default will be used.
+		 *  @type array
+		 *  @default []
+		 *
+		 *  @dtopt Option
+		 *  @name DataTable.defaults.searchCols
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "searchCols": [
+		 *          null,
+		 *          { "search": "My filter" },
+		 *          null,
+		 *          { "search": "^[0-9]", "escapeRegex": false }
+		 *        ]
+		 *      } );
+		 *    } )
+		 */
+		"aoSearchCols": [],
+	
+	
+		/**
+		 * An array of CSS classes that should be applied to displayed rows. This
+		 * array may be of any length, and DataTables will apply each class
+		 * sequentially, looping when required.
+		 *  @type array
+		 *  @default null <i>Will take the values determined by the `oClasses.stripe*`
+		 *    options</i>
+		 *
+		 *  @dtopt Option
+		 *  @name DataTable.defaults.stripeClasses
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
+		 *      } );
+		 *    } )
+		 */
+		"asStripeClasses": null,
+	
+	
+		/**
+		 * Enable or disable automatic column width calculation. This can be disabled
+		 * as an optimisation (it takes some time to calculate the widths) if the
+		 * tables widths are passed in using `columns`.
+		 *  @type boolean
+		 *  @default true
+		 *
+		 *  @dtopt Features
+		 *  @name DataTable.defaults.autoWidth
+		 *
+		 *  @example
+		 *    $(document).ready( function () {
+		 *      $('#example').dataTable( {
+		 *        "autoWidth": false
+		 *      } );
+		 *    } );
+		 */
+		"bAutoWidth": true,
+	
+	
+		/**
+		 * Deferred rendering can provide DataTables with a huge speed boost when you
+		 * are using an Ajax or JS data source for the table. This option, when set to
+		 * true, will cause DataTables to defer the creation of the table elements for
+		 * each row until they are needed for a draw - saving a significant amount of
+		 * time.
+		 *  @type boolean
+		 *  @default false
+		 *
+		 *  @dtopt Features
+		 *  @name DataTable.defaults.deferRender
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "ajax": "sources/arrays.txt",
+		 *        "deferRender": true
+		 *      } );
+		 *    } );
+		 */
+		"bDeferRender": false,
+	
+	
+		/**
+		 * Replace a DataTable which matches the given selector and replace it with
+		 * one which has the properties of the new initialisation object passed. If no
+		 * table matches the selector, then the new DataTable will be constructed as
+		 * per normal.
+		 *  @type boolean
+		 *  @default false
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.destroy
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "srollY": "200px",
+		 *        "paginate": false
+		 *      } );
+		 *
+		 *      // Some time later....
+		 *      $('#example').dataTable( {
+		 *        "filter": false,
+		 *        "destroy": true
+		 *      } );
+		 *    } );
+		 */
+		"bDestroy": false,
+	
+	
+		/**
+		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
+		 * that it allows the end user to input multiple words (space separated) and
+		 * will match a row containing those words, even if not in the order that was
+		 * specified (this allow matching across multiple columns). Note that if you
+		 * wish to use filtering in DataTables this must remain 'true' - to remove the
+		 * default filtering input box and retain filtering abilities, please use
+		 * {@link DataTable.defaults.dom}.
+		 *  @type boolean
+		 *  @default true
+		 *
+		 *  @dtopt Features
+		 *  @name DataTable.defaults.searching
+		 *
+		 *  @example
+		 *    $(document).ready( function () {
+		 *      $('#example').dataTable( {
+		 *        "searching": false
+		 *      } );
+		 *    } );
+		 */
+		"bFilter": true,
+	
+	
+		/**
+		 * Enable or disable the table information display. This shows information
+		 * about the data that is currently visible on the page, including information
+		 * about filtered data if that action is being performed.
+		 *  @type boolean
+		 *  @default true
+		 *
+		 *  @dtopt Features
+		 *  @name DataTable.defaults.info
+		 *
+		 *  @example
+		 *    $(document).ready( function () {
+		 *      $('#example').dataTable( {
+		 *        "info": false
+		 *      } );
+		 *    } );
+		 */
+		"bInfo": true,
+	
+	
+		/**
+		 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
+		 * slightly different and additional mark-up from what DataTables has
+		 * traditionally used).
+		 *  @type boolean
+		 *  @default false
+		 *
+		 *  @dtopt Features
+		 *  @name DataTable.defaults.jQueryUI
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "jQueryUI": true
+		 *      } );
+		 *    } );
+		 */
+		"bJQueryUI": false,
+	
+	
+		/**
+		 * Allows the end user to select the size of a formatted page from a select
+		 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
+		 *  @type boolean
+		 *  @default true
+		 *
+		 *  @dtopt Features
+		 *  @name DataTable.defaults.lengthChange
+		 *
+		 *  @example
+		 *    $(document).ready( function () {
+		 *      $('#example').dataTable( {
+		 *        "lengthChange": false
+		 *      } );
+		 *    } );
+		 */
+		"bLengthChange": true,
+	
+	
+		/**
+		 * Enable or disable pagination.
+		 *  @type boolean
+		 *  @default true
+		 *
+		 *  @dtopt Features
+		 *  @name DataTable.defaults.paging
+		 *
+		 *  @example
+		 *    $(document).ready( function () {
+		 *      $('#example').dataTable( {
+		 *        "paging": false
+		 *      } );
+		 *    } );
+		 */
+		"bPaginate": true,
+	
+	
+		/**
+		 * Enable or disable the display of a 'processing' indicator when the table is
+		 * being processed (e.g. a sort). This is particularly useful for tables with
+		 * large amounts of data where it can take a noticeable amount of time to sort
+		 * the entries.
+		 *  @type boolean
+		 *  @default false
+		 *
+		 *  @dtopt Features
+		 *  @name DataTable.defaults.processing
+		 *
+		 *  @example
+		 *    $(document).ready( function () {
+		 *      $('#example').dataTable( {
+		 *        "processing": true
+		 *      } );
+		 *    } );
+		 */
+		"bProcessing": false,
+	
+	
+		/**
+		 * Retrieve the DataTables object for the given selector. Note that if the
+		 * table has already been initialised, this parameter will cause DataTables
+		 * to simply return the object that has already been set up - it will not take
+		 * account of any changes you might have made to the initialisation object
+		 * passed to DataTables (setting this parameter to true is an acknowledgement
+		 * that you understand this). `destroy` can be used to reinitialise a table if
+		 * you need.
+		 *  @type boolean
+		 *  @default false
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.retrieve
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      initTable();
+		 *      tableActions();
+		 *    } );
+		 *
+		 *    function initTable ()
+		 *    {
+		 *      return $('#example').dataTable( {
+		 *        "scrollY": "200px",
+		 *        "paginate": false,
+		 *        "retrieve": true
+		 *      } );
+		 *    }
+		 *
+		 *    function tableActions ()
+		 *    {
+		 *      var table = initTable();
+		 *      // perform API operations with oTable
+		 *    }
+		 */
+		"bRetrieve": false,
+	
+	
+		/**
+		 * When vertical (y) scrolling is enabled, DataTables will force the height of
+		 * the table's viewport to the given height at all times (useful for layout).
+		 * However, this can look odd when filtering data down to a small data set,
+		 * and the footer is left "floating" further down. This parameter (when
+		 * enabled) will cause DataTables to collapse the table's viewport down when
+		 * the result set will fit within the given Y height.
+		 *  @type boolean
+		 *  @default false
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.scrollCollapse
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "scrollY": "200",
+		 *        "scrollCollapse": true
+		 *      } );
+		 *    } );
+		 */
+		"bScrollCollapse": false,
+	
+	
+		/**
+		 * Configure DataTables to use server-side processing. Note that the
+		 * `ajax` parameter must also be given in order to give DataTables a
+		 * source to obtain the required data for each draw.
+		 *  @type boolean
+		 *  @default false
+		 *
+		 *  @dtopt Features
+		 *  @dtopt Server-side
+		 *  @name DataTable.defaults.serverSide
+		 *
+		 *  @example
+		 *    $(document).ready( function () {
+		 *      $('#example').dataTable( {
+		 *        "serverSide": true,
+		 *        "ajax": "xhr.php"
+		 *      } );
+		 *    } );
+		 */
+		"bServerSide": false,
+	
+	
+		/**
+		 * Enable or disable sorting of columns. Sorting of individual columns can be
+		 * disabled by the `sortable` option for each column.
+		 *  @type boolean
+		 *  @default true
+		 *
+		 *  @dtopt Features
+		 *  @name DataTable.defaults.ordering
+		 *
+		 *  @example
+		 *    $(document).ready( function () {
+		 *      $('#example').dataTable( {
+		 *        "ordering": false
+		 *      } );
+		 *    } );
+		 */
+		"bSort": true,
+	
+	
+		/**
+		 * Enable or display DataTables' ability to sort multiple columns at the
+		 * same time (activated by shift-click by the user).
+		 *  @type boolean
+		 *  @default true
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.orderMulti
+		 *
+		 *  @example
+		 *    // Disable multiple column sorting ability
+		 *    $(document).ready( function () {
+		 *      $('#example').dataTable( {
+		 *        "orderMulti": false
+		 *      } );
+		 *    } );
+		 */
+		"bSortMulti": true,
+	
+	
+		/**
+		 * Allows control over whether DataTables should use the top (true) unique
+		 * cell that is found for a single column, or the bottom (false - default).
+		 * This is useful when using complex headers.
+		 *  @type boolean
+		 *  @default false
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.orderCellsTop
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "orderCellsTop": true
+		 *      } );
+		 *    } );
+		 */
+		"bSortCellsTop": false,
+	
+	
+		/**
+		 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
+		 * `sorting\_3` to the columns which are currently being sorted on. This is
+		 * presented as a feature switch as it can increase processing time (while
+		 * classes are removed and added) so for large data sets you might want to
+		 * turn this off.
+		 *  @type boolean
+		 *  @default true
+		 *
+		 *  @dtopt Features
+		 *  @name DataTable.defaults.orderClasses
+		 *
+		 *  @example
+		 *    $(document).ready( function () {
+		 *      $('#example').dataTable( {
+		 *        "orderClasses": false
+		 *      } );
+		 *    } );
+		 */
+		"bSortClasses": true,
+	
+	
+		/**
+		 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
+		 * used to save table display information such as pagination information,
+		 * display length, filtering and sorting. As such when the end user reloads
+		 * the page the display display will match what thy had previously set up.
+		 *
+		 * Due to the use of `localStorage` the default state saving is not supported
+		 * in IE6 or 7. If state saving is required in those browsers, use
+		 * `stateSaveCallback` to provide a storage solution such as cookies.
+		 *  @type boolean
+		 *  @default false
+		 *
+		 *  @dtopt Features
+		 *  @name DataTable.defaults.stateSave
+		 *
+		 *  @example
+		 *    $(document).ready( function () {
+		 *      $('#example').dataTable( {
+		 *        "stateSave": true
+		 *      } );
+		 *    } );
+		 */
+		"bStateSave": false,
+	
+	
+		/**
+		 * This function is called when a TR element is created (and all TD child
+		 * elements have been inserted), or registered if using a DOM source, allowing
+		 * manipulation of the TR element (adding classes etc).
+		 *  @type function
+		 *  @param {node} row "TR" element for the current row
+		 *  @param {array} data Raw data array for this row
+		 *  @param {int} dataIndex The index of this row in the internal aoData array
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.createdRow
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "createdRow": function( row, data, dataIndex ) {
+		 *          // Bold the grade for all 'A' grade browsers
+		 *          if ( data[4] == "A" )
+		 *          {
+		 *            $('td:eq(4)', row).html( '<b>A</b>' );
+		 *          }
+		 *        }
+		 *      } );
+		 *    } );
+		 */
+		"fnCreatedRow": null,
+	
+	
+		/**
+		 * This function is called on every 'draw' event, and allows you to
+		 * dynamically modify any aspect you want about the created DOM.
+		 *  @type function
+		 *  @param {object} settings DataTables settings object
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.drawCallback
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "drawCallback": function( settings ) {
+		 *          alert( 'DataTables has redrawn the table' );
+		 *        }
+		 *      } );
+		 *    } );
+		 */
+		"fnDrawCallback": null,
+	
+	
+		/**
+		 * Identical to fnHeaderCallback() but for the table footer this function
+		 * allows you to modify the table footer on every 'draw' event.
+		 *  @type function
+		 *  @param {node} foot "TR" element for the footer
+		 *  @param {array} data Full table data (as derived from the original HTML)
+		 *  @param {int} start Index for the current display starting point in the
+		 *    display array
+		 *  @param {int} end Index for the current display ending point in the
+		 *    display array
+		 *  @param {array int} display Index array to translate the visual position
+		 *    to the full data array
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.footerCallback
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "footerCallback": function( tfoot, data, start, end, display ) {
+		 *          tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
+		 *        }
+		 *      } );
+		 *    } )
+		 */
+		"fnFooterCallback": null,
+	
+	
+		/**
+		 * When rendering large numbers in the information element for the table
+		 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
+		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
+		 * rendered as "1,000,000") to help readability for the end user. This
+		 * function will override the default method DataTables uses.
+		 *  @type function
+		 *  @member
+		 *  @param {int} toFormat number to be formatted
+		 *  @returns {string} formatted string for DataTables to show the number
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.formatNumber
+		 *
+		 *  @example
+		 *    // Format a number using a single quote for the separator (note that
+		 *    // this can also be done with the language.thousands option)
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "formatNumber": function ( toFormat ) {
+		 *          return toFormat.toString().replace(
+		 *            /\B(?=(\d{3})+(?!\d))/g, "'"
+		 *          );
+		 *        };
+		 *      } );
+		 *    } );
+		 */
+		"fnFormatNumber": function ( toFormat ) {
+			return toFormat.toString().replace(
+				/\B(?=(\d{3})+(?!\d))/g,
+				this.oLanguage.sThousands
+			);
+		},
+	
+	
+		/**
+		 * This function is called on every 'draw' event, and allows you to
+		 * dynamically modify the header row. This can be used to calculate and
+		 * display useful information about the table.
+		 *  @type function
+		 *  @param {node} head "TR" element for the header
+		 *  @param {array} data Full table data (as derived from the original HTML)
+		 *  @param {int} start Index for the current display starting point in the
+		 *    display array
+		 *  @param {int} end Index for the current display ending point in the
+		 *    display array
+		 *  @param {array int} display Index array to translate the visual position
+		 *    to the full data array
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.headerCallback
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "fheaderCallback": function( head, data, start, end, display ) {
+		 *          head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
+		 *        }
+		 *      } );
+		 *    } )
+		 */
+		"fnHeaderCallback": null,
+	
+	
+		/**
+		 * The information element can be used to convey information about the current
+		 * state of the table. Although the internationalisation options presented by
+		 * DataTables are quite capable of dealing with most customisations, there may
+		 * be times where you wish to customise the string further. This callback
+		 * allows you to do exactly that.
+		 *  @type function
+		 *  @param {object} oSettings DataTables settings object
+		 *  @param {int} start Starting position in data for the draw
+		 *  @param {int} end End position in data for the draw
+		 *  @param {int} max Total number of rows in the table (regardless of
+		 *    filtering)
+		 *  @param {int} total Total number of rows in the data set, after filtering
+		 *  @param {string} pre The string that DataTables has formatted using it's
+		 *    own rules
+		 *  @returns {string} The string to be displayed in the information element.
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.infoCallback
+		 *
+		 *  @example
+		 *    $('#example').dataTable( {
+		 *      "infoCallback": function( settings, start, end, max, total, pre ) {
+		 *        return start +" to "+ end;
+		 *      }
+		 *    } );
+		 */
+		"fnInfoCallback": null,
+	
+	
+		/**
+		 * Called when the table has been initialised. Normally DataTables will
+		 * initialise sequentially and there will be no need for this function,
+		 * however, this does not hold true when using external language information
+		 * since that is obtained using an async XHR call.
+		 *  @type function
+		 *  @param {object} settings DataTables settings object
+		 *  @param {object} json The JSON object request from the server - only
+		 *    present if client-side Ajax sourced data is used
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.initComplete
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "initComplete": function(settings, json) {
+		 *          alert( 'DataTables has finished its initialisation.' );
+		 *        }
+		 *      } );
+		 *    } )
+		 */
+		"fnInitComplete": null,
+	
+	
+		/**
+		 * Called at the very start of each table draw and can be used to cancel the
+		 * draw by returning false, any other return (including undefined) results in
+		 * the full draw occurring).
+		 *  @type function
+		 *  @param {object} settings DataTables settings object
+		 *  @returns {boolean} False will cancel the draw, anything else (including no
+		 *    return) will allow it to complete.
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.preDrawCallback
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "preDrawCallback": function( settings ) {
+		 *          if ( $('#test').val() == 1 ) {
+		 *            return false;
+		 *          }
+		 *        }
+		 *      } );
+		 *    } );
+		 */
+		"fnPreDrawCallback": null,
+	
+	
+		/**
+		 * This function allows you to 'post process' each row after it have been
+		 * generated for each table draw, but before it is rendered on screen. This
+		 * function might be used for setting the row class name etc.
+		 *  @type function
+		 *  @param {node} row "TR" element for the current row
+		 *  @param {array} data Raw data array for this row
+		 *  @param {int} displayIndex The display index for the current table draw
+		 *  @param {int} displayIndexFull The index of the data in the full list of
+		 *    rows (after filtering)
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.rowCallback
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
+		 *          // Bold the grade for all 'A' grade browsers
+		 *          if ( data[4] == "A" ) {
+		 *            $('td:eq(4)', row).html( '<b>A</b>' );
+		 *          }
+		 *        }
+		 *      } );
+		 *    } );
+		 */
+		"fnRowCallback": null,
+	
+	
+		/**
+		 * __Deprecated__ The functionality provided by this parameter has now been
+		 * superseded by that provided through `ajax`, which should be used instead.
+		 *
+		 * This parameter allows you to override the default function which obtains
+		 * the data from the server so something more suitable for your application.
+		 * For example you could use POST data, or pull information from a Gears or
+		 * AIR database.
+		 *  @type function
+		 *  @member
+		 *  @param {string} source HTTP source to obtain the data from (`ajax`)
+		 *  @param {array} data A key/value pair object containing the data to send
+		 *    to the server
+		 *  @param {function} callback to be called on completion of the data get
+		 *    process that will draw the data on the page.
+		 *  @param {object} settings DataTables settings object
+		 *
+		 *  @dtopt Callbacks
+		 *  @dtopt Server-side
+		 *  @name DataTable.defaults.serverData
+		 *
+		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
+		 */
+		"fnServerData": null,
+	
+	
+		/**
+		 * __Deprecated__ The functionality provided by this parameter has now been
+		 * superseded by that provided through `ajax`, which should be used instead.
+		 *
+		 *  It is often useful to send extra data to the server when making an Ajax
+		 * request - for example custom filtering information, and this callback
+		 * function makes it trivial to send extra information to the server. The
+		 * passed in parameter is the data set that has been constructed by
+		 * DataTables, and you can add to this or modify it as you require.
+		 *  @type function
+		 *  @param {array} data Data array (array of objects which are name/value
+		 *    pairs) that has been constructed by DataTables and will be sent to the
+		 *    server. In the case of Ajax sourced data with server-side processing
+		 *    this will be an empty array, for server-side processing there will be a
+		 *    significant number of parameters!
+		 *  @returns {undefined} Ensure that you modify the data array passed in,
+		 *    as this is passed by reference.
+		 *
+		 *  @dtopt Callbacks
+		 *  @dtopt Server-side
+		 *  @name DataTable.defaults.serverParams
+		 *
+		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
+		 */
+		"fnServerParams": null,
+	
+	
+		/**
+		 * Load the table state. With this function you can define from where, and how, the
+		 * state of a table is loaded. By default DataTables will load from `localStorage`
+		 * but you might wish to use a server-side database or cookies.
+		 *  @type function
+		 *  @member
+		 *  @param {object} settings DataTables settings object
+		 *  @return {object} The DataTables state object to be loaded
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.stateLoadCallback
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "stateSave": true,
+		 *        "stateLoadCallback": function (settings) {
+		 *          var o;
+		 *
+		 *          // Send an Ajax request to the server to get the data. Note that
+		 *          // this is a synchronous request.
+		 *          $.ajax( {
+		 *            "url": "/state_load",
+		 *            "async": false,
+		 *            "dataType": "json",
+		 *            "success": function (json) {
+		 *              o = json;
+		 *            }
+		 *          } );
+		 *
+		 *          return o;
+		 *        }
+		 *      } );
+		 *    } );
+		 */
+		"fnStateLoadCallback": function ( settings ) {
+			try {
+				return JSON.parse(
+					(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
+						'DataTables_'+settings.sInstance+'_'+location.pathname
+					)
+				);
+			} catch (e) {}
+		},
+	
+	
+		/**
+		 * Callback which allows modification of the saved state prior to loading that state.
+		 * This callback is called when the table is loading state from the stored data, but
+		 * prior to the settings object being modified by the saved state. Note that for
+		 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
+		 * a plug-in.
+		 *  @type function
+		 *  @param {object} settings DataTables settings object
+		 *  @param {object} data The state object that is to be loaded
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.stateLoadParams
+		 *
+		 *  @example
+		 *    // Remove a saved filter, so filtering is never loaded
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "stateSave": true,
+		 *        "stateLoadParams": function (settings, data) {
+		 *          data.oSearch.sSearch = "";
+		 *        }
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Disallow state loading by returning false
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "stateSave": true,
+		 *        "stateLoadParams": function (settings, data) {
+		 *          return false;
+		 *        }
+		 *      } );
+		 *    } );
+		 */
+		"fnStateLoadParams": null,
+	
+	
+		/**
+		 * Callback that is called when the state has been loaded from the state saving method
+		 * and the DataTables settings object has been modified as a result of the loaded state.
+		 *  @type function
+		 *  @param {object} settings DataTables settings object
+		 *  @param {object} data The state object that was loaded
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.stateLoaded
+		 *
+		 *  @example
+		 *    // Show an alert with the filtering value that was saved
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "stateSave": true,
+		 *        "stateLoaded": function (settings, data) {
+		 *          alert( 'Saved filter was: '+data.oSearch.sSearch );
+		 *        }
+		 *      } );
+		 *    } );
+		 */
+		"fnStateLoaded": null,
+	
+	
+		/**
+		 * Save the table state. This function allows you to define where and how the state
+		 * information for the table is stored By default DataTables will use `localStorage`
+		 * but you might wish to use a server-side database or cookies.
+		 *  @type function
+		 *  @member
+		 *  @param {object} settings DataTables settings object
+		 *  @param {object} data The state object to be saved
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.stateSaveCallback
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "stateSave": true,
+		 *        "stateSaveCallback": function (settings, data) {
+		 *          // Send an Ajax request to the server with the state object
+		 *          $.ajax( {
+		 *            "url": "/state_save",
+		 *            "data": data,
+		 *            "dataType": "json",
+		 *            "method": "POST"
+		 *            "success": function () {}
+		 *          } );
+		 *        }
+		 *      } );
+		 *    } );
+		 */
+		"fnStateSaveCallback": function ( settings, data ) {
+			try {
+				(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
+					'DataTables_'+settings.sInstance+'_'+location.pathname,
+					JSON.stringify( data )
+				);
+			} catch (e) {}
+		},
+	
+	
+		/**
+		 * Callback which allows modification of the state to be saved. Called when the table
+		 * has changed state a new state save is required. This method allows modification of
+		 * the state saving object prior to actually doing the save, including addition or
+		 * other state properties or modification. Note that for plug-in authors, you should
+		 * use the `stateSaveParams` event to save parameters for a plug-in.
+		 *  @type function
+		 *  @param {object} settings DataTables settings object
+		 *  @param {object} data The state object to be saved
+		 *
+		 *  @dtopt Callbacks
+		 *  @name DataTable.defaults.stateSaveParams
+		 *
+		 *  @example
+		 *    // Remove a saved filter, so filtering is never saved
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "stateSave": true,
+		 *        "stateSaveParams": function (settings, data) {
+		 *          data.oSearch.sSearch = "";
+		 *        }
+		 *      } );
+		 *    } );
+		 */
+		"fnStateSaveParams": null,
+	
+	
+		/**
+		 * Duration for which the saved state information is considered valid. After this period
+		 * has elapsed the state will be returned to the default.
+		 * Value is given in seconds.
+		 *  @type int
+		 *  @default 7200 <i>(2 hours)</i>
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.stateDuration
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "stateDuration": 60*60*24; // 1 day
+		 *      } );
+		 *    } )
+		 */
+		"iStateDuration": 7200,
+	
+	
+		/**
+		 * When enabled DataTables will not make a request to the server for the first
+		 * page draw - rather it will use the data already on the page (no sorting etc
+		 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
+		 * is used to indicate that deferred loading is required, but it is also used
+		 * to tell DataTables how many records there are in the full table (allowing
+		 * the information element and pagination to be displayed correctly). In the case
+		 * where a filtering is applied to the table on initial load, this can be
+		 * indicated by giving the parameter as an array, where the first element is
+		 * the number of records available after filtering and the second element is the
+		 * number of records without filtering (allowing the table information element
+		 * to be shown correctly).
+		 *  @type int | array
+		 *  @default null
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.deferLoading
+		 *
+		 *  @example
+		 *    // 57 records available in the table, no filtering applied
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "serverSide": true,
+		 *        "ajax": "scripts/server_processing.php",
+		 *        "deferLoading": 57
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // 57 records after filtering, 100 without filtering (an initial filter applied)
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "serverSide": true,
+		 *        "ajax": "scripts/server_processing.php",
+		 *        "deferLoading": [ 57, 100 ],
+		 *        "search": {
+		 *          "search": "my_filter"
+		 *        }
+		 *      } );
+		 *    } );
+		 */
+		"iDeferLoading": null,
+	
+	
+		/**
+		 * Number of rows to display on a single page when using pagination. If
+		 * feature enabled (`lengthChange`) then the end user will be able to override
+		 * this to a custom setting using a pop-up menu.
+		 *  @type int
+		 *  @default 10
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.pageLength
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "pageLength": 50
+		 *      } );
+		 *    } )
+		 */
+		"iDisplayLength": 10,
+	
+	
+		/**
+		 * Define the starting point for data display when using DataTables with
+		 * pagination. Note that this parameter is the number of records, rather than
+		 * the page number, so if you have 10 records per page and want to start on
+		 * the third page, it should be "20".
+		 *  @type int
+		 *  @default 0
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.displayStart
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "displayStart": 20
+		 *      } );
+		 *    } )
+		 */
+		"iDisplayStart": 0,
+	
+	
+		/**
+		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
+		 * and filtering) by adding a `tabindex` attribute to the required elements. This
+		 * allows you to tab through the controls and press the enter key to activate them.
+		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
+		 * You can overrule this using this parameter if you wish. Use a value of -1 to
+		 * disable built-in keyboard navigation.
+		 *  @type int
+		 *  @default 0
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.tabIndex
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "tabIndex": 1
+		 *      } );
+		 *    } );
+		 */
+		"iTabIndex": 0,
+	
+	
+		/**
+		 * Classes that DataTables assigns to the various components and features
+		 * that it adds to the HTML table. This allows classes to be configured
+		 * during initialisation in addition to through the static
+		 * {@link DataTable.ext.oStdClasses} object).
+		 *  @namespace
+		 *  @name DataTable.defaults.classes
+		 */
+		"oClasses": {},
+	
+	
+		/**
+		 * All strings that DataTables uses in the user interface that it creates
+		 * are defined in this object, allowing you to modified them individually or
+		 * completely replace them all as required.
+		 *  @namespace
+		 *  @name DataTable.defaults.language
+		 */
+		"oLanguage": {
+			/**
+			 * Strings that are used for WAI-ARIA labels and controls only (these are not
+			 * actually visible on the page, but will be read by screenreaders, and thus
+			 * must be internationalised as well).
+			 *  @namespace
+			 *  @name DataTable.defaults.language.aria
+			 */
+			"oAria": {
+				/**
+				 * ARIA label that is added to the table headers when the column may be
+				 * sorted ascending by activing the column (click or return when focused).
+				 * Note that the column header is prefixed to this string.
+				 *  @type string
+				 *  @default : activate to sort column ascending
+				 *
+				 *  @dtopt Language
+				 *  @name DataTable.defaults.language.aria.sortAscending
+				 *
+				 *  @example
+				 *    $(document).ready( function() {
+				 *      $('#example').dataTable( {
+				 *        "language": {
+				 *          "aria": {
+				 *            "sortAscending": " - click/return to sort ascending"
+				 *          }
+				 *        }
+				 *      } );
+				 *    } );
+				 */
+				"sSortAscending": ": activate to sort column ascending",
+	
+				/**
+				 * ARIA label that is added to the table headers when the column may be
+				 * sorted descending by activing the column (click or return when focused).
+				 * Note that the column header is prefixed to this string.
+				 *  @type string
+				 *  @default : activate to sort column ascending
+				 *
+				 *  @dtopt Language
+				 *  @name DataTable.defaults.language.aria.sortDescending
+				 *
+				 *  @example
+				 *    $(document).ready( function() {
+				 *      $('#example').dataTable( {
+				 *        "language": {
+				 *          "aria": {
+				 *            "sortDescending": " - click/return to sort descending"
+				 *          }
+				 *        }
+				 *      } );
+				 *    } );
+				 */
+				"sSortDescending": ": activate to sort column descending"
+			},
+	
+			/**
+			 * Pagination string used by DataTables for the built-in pagination
+			 * control types.
+			 *  @namespace
+			 *  @name DataTable.defaults.language.paginate
+			 */
+			"oPaginate": {
+				/**
+				 * Text to use when using the 'full_numbers' type of pagination for the
+				 * button to take the user to the first page.
+				 *  @type string
+				 *  @default First
+				 *
+				 *  @dtopt Language
+				 *  @name DataTable.defaults.language.paginate.first
+				 *
+				 *  @example
+				 *    $(document).ready( function() {
+				 *      $('#example').dataTable( {
+				 *        "language": {
+				 *          "paginate": {
+				 *            "first": "First page"
+				 *          }
+				 *        }
+				 *      } );
+				 *    } );
+				 */
+				"sFirst": "First",
+	
+	
+				/**
+				 * Text to use when using the 'full_numbers' type of pagination for the
+				 * button to take the user to the last page.
+				 *  @type string
+				 *  @default Last
+				 *
+				 *  @dtopt Language
+				 *  @name DataTable.defaults.language.paginate.last
+				 *
+				 *  @example
+				 *    $(document).ready( function() {
+				 *      $('#example').dataTable( {
+				 *        "language": {
+				 *          "paginate": {
+				 *            "last": "Last page"
+				 *          }
+				 *        }
+				 *      } );
+				 *    } );
+				 */
+				"sLast": "Last",
+	
+	
+				/**
+				 * Text to use for the 'next' pagination button (to take the user to the
+				 * next page).
+				 *  @type string
+				 *  @default Next
+				 *
+				 *  @dtopt Language
+				 *  @name DataTable.defaults.language.paginate.next
+				 *
+				 *  @example
+				 *    $(document).ready( function() {
+				 *      $('#example').dataTable( {
+				 *        "language": {
+				 *          "paginate": {
+				 *            "next": "Next page"
+				 *          }
+				 *        }
+				 *      } );
+				 *    } );
+				 */
+				"sNext": "Next",
+	
+	
+				/**
+				 * Text to use for the 'previous' pagination button (to take the user to
+				 * the previous page).
+				 *  @type string
+				 *  @default Previous
+				 *
+				 *  @dtopt Language
+				 *  @name DataTable.defaults.language.paginate.previous
+				 *
+				 *  @example
+				 *    $(document).ready( function() {
+				 *      $('#example').dataTable( {
+				 *        "language": {
+				 *          "paginate": {
+				 *            "previous": "Previous page"
+				 *          }
+				 *        }
+				 *      } );
+				 *    } );
+				 */
+				"sPrevious": "Previous"
+			},
+	
+			/**
+			 * This string is shown in preference to `zeroRecords` when the table is
+			 * empty of data (regardless of filtering). Note that this is an optional
+			 * parameter - if it is not given, the value of `zeroRecords` will be used
+			 * instead (either the default or given value).
+			 *  @type string
+			 *  @default No data available in table
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.emptyTable
+			 *
+			 *  @example
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "emptyTable": "No data available in table"
+			 *        }
+			 *      } );
+			 *    } );
+			 */
+			"sEmptyTable": "No data available in table",
+	
+	
+			/**
+			 * This string gives information to the end user about the information
+			 * that is current on display on the page. The following tokens can be
+			 * used in the string and will be dynamically replaced as the table
+			 * display updates. This tokens can be placed anywhere in the string, or
+			 * removed as needed by the language requires:
+			 *
+			 * * `\_START\_` - Display index of the first record on the current page
+			 * * `\_END\_` - Display index of the last record on the current page
+			 * * `\_TOTAL\_` - Number of records in the table after filtering
+			 * * `\_MAX\_` - Number of records in the table without filtering
+			 * * `\_PAGE\_` - Current page number
+			 * * `\_PAGES\_` - Total number of pages of data in the table
+			 *
+			 *  @type string
+			 *  @default Showing _START_ to _END_ of _TOTAL_ entries
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.info
+			 *
+			 *  @example
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "info": "Showing page _PAGE_ of _PAGES_"
+			 *        }
+			 *      } );
+			 *    } );
+			 */
+			"sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
+	
+	
+			/**
+			 * Display information string for when the table is empty. Typically the
+			 * format of this string should match `info`.
+			 *  @type string
+			 *  @default Showing 0 to 0 of 0 entries
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.infoEmpty
+			 *
+			 *  @example
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "infoEmpty": "No entries to show"
+			 *        }
+			 *      } );
+			 *    } );
+			 */
+			"sInfoEmpty": "Showing 0 to 0 of 0 entries",
+	
+	
+			/**
+			 * When a user filters the information in a table, this string is appended
+			 * to the information (`info`) to give an idea of how strong the filtering
+			 * is. The variable _MAX_ is dynamically updated.
+			 *  @type string
+			 *  @default (filtered from _MAX_ total entries)
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.infoFiltered
+			 *
+			 *  @example
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "infoFiltered": " - filtering from _MAX_ records"
+			 *        }
+			 *      } );
+			 *    } );
+			 */
+			"sInfoFiltered": "(filtered from _MAX_ total entries)",
+	
+	
+			/**
+			 * If can be useful to append extra information to the info string at times,
+			 * and this variable does exactly that. This information will be appended to
+			 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
+			 * being used) at all times.
+			 *  @type string
+			 *  @default <i>Empty string</i>
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.infoPostFix
+			 *
+			 *  @example
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "infoPostFix": "All records shown are derived from real information."
+			 *        }
+			 *      } );
+			 *    } );
+			 */
+			"sInfoPostFix": "",
+	
+	
+			/**
+			 * This decimal place operator is a little different from the other
+			 * language options since DataTables doesn't output floating point
+			 * numbers, so it won't ever use this for display of a number. Rather,
+			 * what this parameter does is modify the sort methods of the table so
+			 * that numbers which are in a format which has a character other than
+			 * a period (`.`) as a decimal place will be sorted numerically.
+			 *
+			 * Note that numbers with different decimal places cannot be shown in
+			 * the same table and still be sortable, the table must be consistent.
+			 * However, multiple different tables on the page can use different
+			 * decimal place characters.
+			 *  @type string
+			 *  @default 
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.decimal
+			 *
+			 *  @example
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "decimal": ","
+			 *          "thousands": "."
+			 *        }
+			 *      } );
+			 *    } );
+			 */
+			"sDecimal": "",
+	
+	
+			/**
+			 * DataTables has a build in number formatter (`formatNumber`) which is
+			 * used to format large numbers that are used in the table information.
+			 * By default a comma is used, but this can be trivially changed to any
+			 * character you wish with this parameter.
+			 *  @type string
+			 *  @default ,
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.thousands
+			 *
+			 *  @example
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "thousands": "'"
+			 *        }
+			 *      } );
+			 *    } );
+			 */
+			"sThousands": ",",
+	
+	
+			/**
+			 * Detail the action that will be taken when the drop down menu for the
+			 * pagination length option is changed. The '_MENU_' variable is replaced
+			 * with a default select list of 10, 25, 50 and 100, and can be replaced
+			 * with a custom select box if required.
+			 *  @type string
+			 *  @default Show _MENU_ entries
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.lengthMenu
+			 *
+			 *  @example
+			 *    // Language change only
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "lengthMenu": "Display _MENU_ records"
+			 *        }
+			 *      } );
+			 *    } );
+			 *
+			 *  @example
+			 *    // Language and options change
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "lengthMenu": 'Display <select>'+
+			 *            '<option value="10">10</option>'+
+			 *            '<option value="20">20</option>'+
+			 *            '<option value="30">30</option>'+
+			 *            '<option value="40">40</option>'+
+			 *            '<option value="50">50</option>'+
+			 *            '<option value="-1">All</option>'+
+			 *            '</select> records'
+			 *        }
+			 *      } );
+			 *    } );
+			 */
+			"sLengthMenu": "Show _MENU_ entries",
+	
+	
+			/**
+			 * When using Ajax sourced data and during the first draw when DataTables is
+			 * gathering the data, this message is shown in an empty row in the table to
+			 * indicate to the end user the the data is being loaded. Note that this
+			 * parameter is not used when loading data by server-side processing, just
+			 * Ajax sourced data with client-side processing.
+			 *  @type string
+			 *  @default Loading...
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.loadingRecords
+			 *
+			 *  @example
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "loadingRecords": "Please wait - loading..."
+			 *        }
+			 *      } );
+			 *    } );
+			 */
+			"sLoadingRecords": "Loading...",
+	
+	
+			/**
+			 * Text which is displayed when the table is processing a user action
+			 * (usually a sort command or similar).
+			 *  @type string
+			 *  @default Processing...
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.processing
+			 *
+			 *  @example
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "processing": "DataTables is currently busy"
+			 *        }
+			 *      } );
+			 *    } );
+			 */
+			"sProcessing": "Processing...",
+	
+	
+			/**
+			 * Details the actions that will be taken when the user types into the
+			 * filtering input text box. The variable "_INPUT_", if used in the string,
+			 * is replaced with the HTML text box for the filtering input allowing
+			 * control over where it appears in the string. If "_INPUT_" is not given
+			 * then the input box is appended to the string automatically.
+			 *  @type string
+			 *  @default Search:
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.search
+			 *
+			 *  @example
+			 *    // Input text box will be appended at the end automatically
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "search": "Filter records:"
+			 *        }
+			 *      } );
+			 *    } );
+			 *
+			 *  @example
+			 *    // Specify where the filter should appear
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "search": "Apply filter _INPUT_ to table"
+			 *        }
+			 *      } );
+			 *    } );
+			 */
+			"sSearch": "Search:",
+	
+	
+			/**
+			 * Assign a `placeholder` attribute to the search `input` element
+			 *  @type string
+			 *  @default 
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.searchPlaceholder
+			 */
+			"sSearchPlaceholder": "",
+	
+	
+			/**
+			 * All of the language information can be stored in a file on the
+			 * server-side, which DataTables will look up if this parameter is passed.
+			 * It must store the URL of the language file, which is in a JSON format,
+			 * and the object has the same properties as the oLanguage object in the
+			 * initialiser object (i.e. the above parameters). Please refer to one of
+			 * the example language files to see how this works in action.
+			 *  @type string
+			 *  @default <i>Empty string - i.e. disabled</i>
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.url
+			 *
+			 *  @example
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
+			 *        }
+			 *      } );
+			 *    } );
+			 */
+			"sUrl": "",
+	
+	
+			/**
+			 * Text shown inside the table records when the is no information to be
+			 * displayed after filtering. `emptyTable` is shown when there is simply no
+			 * information in the table at all (regardless of filtering).
+			 *  @type string
+			 *  @default No matching records found
+			 *
+			 *  @dtopt Language
+			 *  @name DataTable.defaults.language.zeroRecords
+			 *
+			 *  @example
+			 *    $(document).ready( function() {
+			 *      $('#example').dataTable( {
+			 *        "language": {
+			 *          "zeroRecords": "No records to display"
+			 *        }
+			 *      } );
+			 *    } );
+			 */
+			"sZeroRecords": "No matching records found"
+		},
+	
+	
+		/**
+		 * This parameter allows you to have define the global filtering state at
+		 * initialisation time. As an object the `search` parameter must be
+		 * defined, but all other parameters are optional. When `regex` is true,
+		 * the search string will be treated as a regular expression, when false
+		 * (default) it will be treated as a straight string. When `smart`
+		 * DataTables will use it's smart filtering methods (to word match at
+		 * any point in the data), when false this will not be done.
+		 *  @namespace
+		 *  @extends DataTable.models.oSearch
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.search
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "search": {"search": "Initial search"}
+		 *      } );
+		 *    } )
+		 */
+		"oSearch": $.extend( {}, DataTable.models.oSearch ),
+	
+	
+		/**
+		 * __Deprecated__ The functionality provided by this parameter has now been
+		 * superseded by that provided through `ajax`, which should be used instead.
+		 *
+		 * By default DataTables will look for the property `data` (or `aaData` for
+		 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
+		 * source or for server-side processing - this parameter allows that
+		 * property to be changed. You can use Javascript dotted object notation to
+		 * get a data source for multiple levels of nesting.
+		 *  @type string
+		 *  @default data
+		 *
+		 *  @dtopt Options
+		 *  @dtopt Server-side
+		 *  @name DataTable.defaults.ajaxDataProp
+		 *
+		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
+		 */
+		"sAjaxDataProp": "data",
+	
+	
+		/**
+		 * __Deprecated__ The functionality provided by this parameter has now been
+		 * superseded by that provided through `ajax`, which should be used instead.
+		 *
+		 * You can instruct DataTables to load data from an external
+		 * source using this parameter (use aData if you want to pass data in you
+		 * already have). Simply provide a url a JSON object can be obtained from.
+		 *  @type string
+		 *  @default null
+		 *
+		 *  @dtopt Options
+		 *  @dtopt Server-side
+		 *  @name DataTable.defaults.ajaxSource
+		 *
+		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
+		 */
+		"sAjaxSource": null,
+	
+	
+		/**
+		 * This initialisation variable allows you to specify exactly where in the
+		 * DOM you want DataTables to inject the various controls it adds to the page
+		 * (for example you might want the pagination controls at the top of the
+		 * table). DIV elements (with or without a custom class) can also be added to
+		 * aid styling. The follow syntax is used:
+		 *   <ul>
+		 *     <li>The following options are allowed:
+		 *       <ul>
+		 *         <li>'l' - Length changing</li>
+		 *         <li>'f' - Filtering input</li>
+		 *         <li>'t' - The table!</li>
+		 *         <li>'i' - Information</li>
+		 *         <li>'p' - Pagination</li>
+		 *         <li>'r' - pRocessing</li>
+		 *       </ul>
+		 *     </li>
+		 *     <li>The following constants are allowed:
+		 *       <ul>
+		 *         <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
+		 *         <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
+		 *       </ul>
+		 *     </li>
+		 *     <li>The following syntax is expected:
+		 *       <ul>
+		 *         <li>'&lt;' and '&gt;' - div elements</li>
+		 *         <li>'&lt;"class" and '&gt;' - div with a class</li>
+		 *         <li>'&lt;"#id" and '&gt;' - div with an ID</li>
+		 *       </ul>
+		 *     </li>
+		 *     <li>Examples:
+		 *       <ul>
+		 *         <li>'&lt;"wrapper"flipt&gt;'</li>
+		 *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
+		 *       </ul>
+		 *     </li>
+		 *   </ul>
+		 *  @type string
+		 *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
+		 *    <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.dom
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
+		 *      } );
+		 *    } );
+		 */
+		"sDom": "lfrtip",
+	
+	
+		/**
+		 * Search delay option. This will throttle full table searches that use the
+		 * DataTables provided search input element (it does not effect calls to
+		 * `dt-api search()`, providing a delay before the search is made.
+		 *  @type integer
+		 *  @default 0
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.searchDelay
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "searchDelay": 200
+		 *      } );
+		 *    } )
+		 */
+		"searchDelay": null,
+	
+	
+		/**
+		 * DataTables features four different built-in options for the buttons to
+		 * display for pagination control:
+		 *
+		 * * `simple` - 'Previous' and 'Next' buttons only
+		 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
+		 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
+		 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
+		 *   page numbers
+		 *  
+		 * Further methods can be added using {@link DataTable.ext.oPagination}.
+		 *  @type string
+		 *  @default simple_numbers
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.pagingType
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "pagingType": "full_numbers"
+		 *      } );
+		 *    } )
+		 */
+		"sPaginationType": "simple_numbers",
+	
+	
+		/**
+		 * Enable horizontal scrolling. When a table is too wide to fit into a
+		 * certain layout, or you have a large number of columns in the table, you
+		 * can enable x-scrolling to show the table in a viewport, which can be
+		 * scrolled. This property can be `true` which will allow the table to
+		 * scroll horizontally when needed, or any CSS unit, or a number (in which
+		 * case it will be treated as a pixel measurement). Setting as simply `true`
+		 * is recommended.
+		 *  @type boolean|string
+		 *  @default <i>blank string - i.e. disabled</i>
+		 *
+		 *  @dtopt Features
+		 *  @name DataTable.defaults.scrollX
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "scrollX": true,
+		 *        "scrollCollapse": true
+		 *      } );
+		 *    } );
+		 */
+		"sScrollX": "",
+	
+	
+		/**
+		 * This property can be used to force a DataTable to use more width than it
+		 * might otherwise do when x-scrolling is enabled. For example if you have a
+		 * table which requires to be well spaced, this parameter is useful for
+		 * "over-sizing" the table, and thus forcing scrolling. This property can by
+		 * any CSS unit, or a number (in which case it will be treated as a pixel
+		 * measurement).
+		 *  @type string
+		 *  @default <i>blank string - i.e. disabled</i>
+		 *
+		 *  @dtopt Options
+		 *  @name DataTable.defaults.scrollXInner
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "scrollX": "100%",
+		 *        "scrollXInner": "110%"
+		 *      } );
+		 *    } );
+		 */
+		"sScrollXInner": "",
+	
+	
+		/**
+		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
+		 * to the given height, and enable scrolling for any data which overflows the
+		 * current viewport. This can be used as an alternative to paging to display
+		 * a lot of data in a small area (although paging and scrolling can both be
+		 * enabled at the same time). This property can be any CSS unit, or a number
+		 * (in which case it will be treated as a pixel measurement).
+		 *  @type string
+		 *  @default <i>blank string - i.e. disabled</i>
+		 *
+		 *  @dtopt Features
+		 *  @name DataTable.defaults.scrollY
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "scrollY": "200px",
+		 *        "paginate": false
+		 *      } );
+		 *    } );
+		 */
+		"sScrollY": "",
+	
+	
+		/**
+		 * __Deprecated__ The functionality provided by this parameter has now been
+		 * superseded by that provided through `ajax`, which should be used instead.
+		 *
+		 * Set the HTTP method that is used to make the Ajax call for server-side
+		 * processing or Ajax sourced data.
+		 *  @type string
+		 *  @default GET
+		 *
+		 *  @dtopt Options
+		 *  @dtopt Server-side
+		 *  @name DataTable.defaults.serverMethod
+		 *
+		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
+		 */
+		"sServerMethod": "GET",
+	
+	
+		/**
+		 * DataTables makes use of renderers when displaying HTML elements for
+		 * a table. These renderers can be added or modified by plug-ins to
+		 * generate suitable mark-up for a site. For example the Bootstrap
+		 * integration plug-in for DataTables uses a paging button renderer to
+		 * display pagination buttons in the mark-up required by Bootstrap.
+		 *
+		 * For further information about the renderers available see
+		 * DataTable.ext.renderer
+		 *  @type string|object
+		 *  @default null
+		 *
+		 *  @name DataTable.defaults.renderer
+		 *
+		 */
+		"renderer": null
+	};
+	
+	_fnHungarianMap( DataTable.defaults );
+	
+	
+	
+	/*
+	 * Developer note - See note in model.defaults.js about the use of Hungarian
+	 * notation and camel case.
+	 */
+	
+	/**
+	 * Column options that can be given to DataTables at initialisation time.
+	 *  @namespace
+	 */
+	DataTable.defaults.column = {
+		/**
+		 * Define which column(s) an order will occur on for this column. This
+		 * allows a column's ordering to take multiple columns into account when
+		 * doing a sort or use the data from a different column. For example first
+		 * name / last name columns make sense to do a multi-column sort over the
+		 * two columns.
+		 *  @type array|int
+		 *  @default null <i>Takes the value of the column index automatically</i>
+		 *
+		 *  @name DataTable.defaults.column.orderData
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Using `columnDefs`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [
+		 *          { "orderData": [ 0, 1 ], "targets": [ 0 ] },
+		 *          { "orderData": [ 1, 0 ], "targets": [ 1 ] },
+		 *          { "orderData": 2, "targets": [ 2 ] }
+		 *        ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using `columns`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columns": [
+		 *          { "orderData": [ 0, 1 ] },
+		 *          { "orderData": [ 1, 0 ] },
+		 *          { "orderData": 2 },
+		 *          null,
+		 *          null
+		 *        ]
+		 *      } );
+		 *    } );
+		 */
+		"aDataSort": null,
+		"iDataSort": -1,
+	
+	
+		/**
+		 * You can control the default ordering direction, and even alter the
+		 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
+		 * using this parameter.
+		 *  @type array
+		 *  @default [ 'asc', 'desc' ]
+		 *
+		 *  @name DataTable.defaults.column.orderSequence
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Using `columnDefs`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [
+		 *          { "orderSequence": [ "asc" ], "targets": [ 1 ] },
+		 *          { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
+		 *          { "orderSequence": [ "desc" ], "targets": [ 3 ] }
+		 *        ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using `columns`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columns": [
+		 *          null,
+		 *          { "orderSequence": [ "asc" ] },
+		 *          { "orderSequence": [ "desc", "asc", "asc" ] },
+		 *          { "orderSequence": [ "desc" ] },
+		 *          null
+		 *        ]
+		 *      } );
+		 *    } );
+		 */
+		"asSorting": [ 'asc', 'desc' ],
+	
+	
+		/**
+		 * Enable or disable filtering on the data in this column.
+		 *  @type boolean
+		 *  @default true
+		 *
+		 *  @name DataTable.defaults.column.searchable
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Using `columnDefs`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [
+		 *          { "searchable": false, "targets": [ 0 ] }
+		 *        ] } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using `columns`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columns": [
+		 *          { "searchable": false },
+		 *          null,
+		 *          null,
+		 *          null,
+		 *          null
+		 *        ] } );
+		 *    } );
+		 */
+		"bSearchable": true,
+	
+	
+		/**
+		 * Enable or disable ordering on this column.
+		 *  @type boolean
+		 *  @default true
+		 *
+		 *  @name DataTable.defaults.column.orderable
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Using `columnDefs`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [
+		 *          { "orderable": false, "targets": [ 0 ] }
+		 *        ] } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using `columns`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columns": [
+		 *          { "orderable": false },
+		 *          null,
+		 *          null,
+		 *          null,
+		 *          null
+		 *        ] } );
+		 *    } );
+		 */
+		"bSortable": true,
+	
+	
+		/**
+		 * Enable or disable the display of this column.
+		 *  @type boolean
+		 *  @default true
+		 *
+		 *  @name DataTable.defaults.column.visible
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Using `columnDefs`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [
+		 *          { "visible": false, "targets": [ 0 ] }
+		 *        ] } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using `columns`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columns": [
+		 *          { "visible": false },
+		 *          null,
+		 *          null,
+		 *          null,
+		 *          null
+		 *        ] } );
+		 *    } );
+		 */
+		"bVisible": true,
+	
+	
+		/**
+		 * Developer definable function that is called whenever a cell is created (Ajax source,
+		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
+		 * allowing you to modify the DOM element (add background colour for example) when the
+		 * element is available.
+		 *  @type function
+		 *  @param {element} td The TD node that has been created
+		 *  @param {*} cellData The Data for the cell
+		 *  @param {array|object} rowData The data for the whole row
+		 *  @param {int} row The row index for the aoData data store
+		 *  @param {int} col The column index for aoColumns
+		 *
+		 *  @name DataTable.defaults.column.createdCell
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [ {
+		 *          "targets": [3],
+		 *          "createdCell": function (td, cellData, rowData, row, col) {
+		 *            if ( cellData == "1.7" ) {
+		 *              $(td).css('color', 'blue')
+		 *            }
+		 *          }
+		 *        } ]
+		 *      });
+		 *    } );
+		 */
+		"fnCreatedCell": null,
+	
+	
+		/**
+		 * This parameter has been replaced by `data` in DataTables to ensure naming
+		 * consistency. `dataProp` can still be used, as there is backwards
+		 * compatibility in DataTables for this option, but it is strongly
+		 * recommended that you use `data` in preference to `dataProp`.
+		 *  @name DataTable.defaults.column.dataProp
+		 */
+	
+	
+		/**
+		 * This property can be used to read data from any data source property,
+		 * including deeply nested objects / properties. `data` can be given in a
+		 * number of different ways which effect its behaviour:
+		 *
+		 * * `integer` - treated as an array index for the data source. This is the
+		 *   default that DataTables uses (incrementally increased for each column).
+		 * * `string` - read an object property from the data source. There are
+		 *   three 'special' options that can be used in the string to alter how
+		 *   DataTables reads the data from the source object:
+		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
+		 *      Javascript to read from nested objects, so to can the options
+		 *      specified in `data`. For example: `browser.version` or
+		 *      `browser.name`. If your object parameter name contains a period, use
+		 *      `\\` to escape it - i.e. `first\\.name`.
+		 *    * `[]` - Array notation. DataTables can automatically combine data
+		 *      from and array source, joining the data with the characters provided
+		 *      between the two brackets. For example: `name[, ]` would provide a
+		 *      comma-space separated list from the source array. If no characters
+		 *      are provided between the brackets, the original array source is
+		 *      returned.
+		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
+		 *      execute a function of the name given. For example: `browser()` for a
+		 *      simple function on the data source, `browser.version()` for a
+		 *      function in a nested property or even `browser().version` to get an
+		 *      object property if the function called returns an object. Note that
+		 *      function notation is recommended for use in `render` rather than
+		 *      `data` as it is much simpler to use as a renderer.
+		 * * `null` - use the original data source for the row rather than plucking
+		 *   data directly from it. This action has effects on two other
+		 *   initialisation options:
+		 *    * `defaultContent` - When null is given as the `data` option and
+		 *      `defaultContent` is specified for the column, the value defined by
+		 *      `defaultContent` will be used for the cell.
+		 *    * `render` - When null is used for the `data` option and the `render`
+		 *      option is specified for the column, the whole data source for the
+		 *      row is used for the renderer.
+		 * * `function` - the function given will be executed whenever DataTables
+		 *   needs to set or get the data for a cell in the column. The function
+		 *   takes three parameters:
+		 *    * Parameters:
+		 *      * `{array|object}` The data source for the row
+		 *      * `{string}` The type call data requested - this will be 'set' when
+		 *        setting data or 'filter', 'display', 'type', 'sort' or undefined
+		 *        when gathering data. Note that when `undefined` is given for the
+		 *        type DataTables expects to get the raw data for the object back<
+		 *      * `{*}` Data to set when the second parameter is 'set'.
+		 *    * Return:
+		 *      * The return value from the function is not required when 'set' is
+		 *        the type of call, but otherwise the return is what will be used
+		 *        for the data requested.
+		 *
+		 * Note that `data` is a getter and setter option. If you just require
+		 * formatting of data for output, you will likely want to use `render` which
+		 * is simply a getter and thus simpler to use.
+		 *
+		 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
+		 * name change reflects the flexibility of this property and is consistent
+		 * with the naming of mRender. If 'mDataProp' is given, then it will still
+		 * be used by DataTables, as it automatically maps the old name to the new
+		 * if required.
+		 *
+		 *  @type string|int|function|null
+		 *  @default null <i>Use automatically calculated column index</i>
+		 *
+		 *  @name DataTable.defaults.column.data
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Read table data from objects
+		 *    // JSON structure for each row:
+		 *    //   {
+		 *    //      "engine": {value},
+		 *    //      "browser": {value},
+		 *    //      "platform": {value},
+		 *    //      "version": {value},
+		 *    //      "grade": {value}
+		 *    //   }
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "ajaxSource": "sources/objects.txt",
+		 *        "columns": [
+		 *          { "data": "engine" },
+		 *          { "data": "browser" },
+		 *          { "data": "platform" },
+		 *          { "data": "version" },
+		 *          { "data": "grade" }
+		 *        ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Read information from deeply nested objects
+		 *    // JSON structure for each row:
+		 *    //   {
+		 *    //      "engine": {value},
+		 *    //      "browser": {value},
+		 *    //      "platform": {
+		 *    //         "inner": {value}
+		 *    //      },
+		 *    //      "details": [
+		 *    //         {value}, {value}
+		 *    //      ]
+		 *    //   }
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "ajaxSource": "sources/deep.txt",
+		 *        "columns": [
+		 *          { "data": "engine" },
+		 *          { "data": "browser" },
+		 *          { "data": "platform.inner" },
+		 *          { "data": "platform.details.0" },
+		 *          { "data": "platform.details.1" }
+		 *        ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using `data` as a function to provide different information for
+		 *    // sorting, filtering and display. In this case, currency (price)
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [ {
+		 *          "targets": [ 0 ],
+		 *          "data": function ( source, type, val ) {
+		 *            if (type === 'set') {
+		 *              source.price = val;
+		 *              // Store the computed dislay and filter values for efficiency
+		 *              source.price_display = val=="" ? "" : "$"+numberFormat(val);
+		 *              source.price_filter  = val=="" ? "" : "$"+numberFormat(val)+" "+val;
+		 *              return;
+		 *            }
+		 *            else if (type === 'display') {
+		 *              return source.price_display;
+		 *            }
+		 *            else if (type === 'filter') {
+		 *              return source.price_filter;
+		 *            }
+		 *            // 'sort', 'type' and undefined all just use the integer
+		 *            return source.price;
+		 *          }
+		 *        } ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using default content
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [ {
+		 *          "targets": [ 0 ],
+		 *          "data": null,
+		 *          "defaultContent": "Click to edit"
+		 *        } ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using array notation - outputting a list from an array
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [ {
+		 *          "targets": [ 0 ],
+		 *          "data": "name[, ]"
+		 *        } ]
+		 *      } );
+		 *    } );
+		 *
+		 */
+		"mData": null,
+	
+	
+		/**
+		 * This property is the rendering partner to `data` and it is suggested that
+		 * when you want to manipulate data for display (including filtering,
+		 * sorting etc) without altering the underlying data for the table, use this
+		 * property. `render` can be considered to be the the read only companion to
+		 * `data` which is read / write (then as such more complex). Like `data`
+		 * this option can be given in a number of different ways to effect its
+		 * behaviour:
+		 *
+		 * * `integer` - treated as an array index for the data source. This is the
+		 *   default that DataTables uses (incrementally increased for each column).
+		 * * `string` - read an object property from the data source. There are
+		 *   three 'special' options that can be used in the string to alter how
+		 *   DataTables reads the data from the source object:
+		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
+		 *      Javascript to read from nested objects, so to can the options
+		 *      specified in `data`. For example: `browser.version` or
+		 *      `browser.name`. If your object parameter name contains a period, use
+		 *      `\\` to escape it - i.e. `first\\.name`.
+		 *    * `[]` - Array notation. DataTables can automatically combine data
+		 *      from and array source, joining the data with the characters provided
+		 *      between the two brackets. For example: `name[, ]` would provide a
+		 *      comma-space separated list from the source array. If no characters
+		 *      are provided between the brackets, the original array source is
+		 *      returned.
+		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
+		 *      execute a function of the name given. For example: `browser()` for a
+		 *      simple function on the data source, `browser.version()` for a
+		 *      function in a nested property or even `browser().version` to get an
+		 *      object property if the function called returns an object.
+		 * * `object` - use different data for the different data types requested by
+		 *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
+		 *   of the object is the data type the property refers to and the value can
+		 *   defined using an integer, string or function using the same rules as
+		 *   `render` normally does. Note that an `_` option _must_ be specified.
+		 *   This is the default value to use if you haven't specified a value for
+		 *   the data type requested by DataTables.
+		 * * `function` - the function given will be executed whenever DataTables
+		 *   needs to set or get the data for a cell in the column. The function
+		 *   takes three parameters:
+		 *    * Parameters:
+		 *      * {array|object} The data source for the row (based on `data`)
+		 *      * {string} The type call data requested - this will be 'filter',
+		 *        'display', 'type' or 'sort'.
+		 *      * {array|object} The full data source for the row (not based on
+		 *        `data`)
+		 *    * Return:
+		 *      * The return value from the function is what will be used for the
+		 *        data requested.
+		 *
+		 *  @type string|int|function|object|null
+		 *  @default null Use the data source value.
+		 *
+		 *  @name DataTable.defaults.column.render
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Create a comma separated list from an array of objects
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "ajaxSource": "sources/deep.txt",
+		 *        "columns": [
+		 *          { "data": "engine" },
+		 *          { "data": "browser" },
+		 *          {
+		 *            "data": "platform",
+		 *            "render": "[, ].name"
+		 *          }
+		 *        ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Execute a function to obtain data
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [ {
+		 *          "targets": [ 0 ],
+		 *          "data": null, // Use the full data source object for the renderer's source
+		 *          "render": "browserName()"
+		 *        } ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // As an object, extracting different data for the different types
+		 *    // This would be used with a data source such as:
+		 *    //   { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
+		 *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
+		 *    // (which has both forms) is used for filtering for if a user inputs either format, while
+		 *    // the formatted phone number is the one that is shown in the table.
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [ {
+		 *          "targets": [ 0 ],
+		 *          "data": null, // Use the full data source object for the renderer's source
+		 *          "render": {
+		 *            "_": "phone",
+		 *            "filter": "phone_filter",
+		 *            "display": "phone_display"
+		 *          }
+		 *        } ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Use as a function to create a link from the data source
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [ {
+		 *          "targets": [ 0 ],
+		 *          "data": "download_link",
+		 *          "render": function ( data, type, full ) {
+		 *            return '<a href="'+data+'">Download</a>';
+		 *          }
+		 *        } ]
+		 *      } );
+		 *    } );
+		 */
+		"mRender": null,
+	
+	
+		/**
+		 * Change the cell type created for the column - either TD cells or TH cells. This
+		 * can be useful as TH cells have semantic meaning in the table body, allowing them
+		 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
+		 *  @type string
+		 *  @default td
+		 *
+		 *  @name DataTable.defaults.column.cellType
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Make the first column use TH cells
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [ {
+		 *          "targets": [ 0 ],
+		 *          "cellType": "th"
+		 *        } ]
+		 *      } );
+		 *    } );
+		 */
+		"sCellType": "td",
+	
+	
+		/**
+		 * Class to give to each cell in this column.
+		 *  @type string
+		 *  @default <i>Empty string</i>
+		 *
+		 *  @name DataTable.defaults.column.class
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Using `columnDefs`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [
+		 *          { "class": "my_class", "targets": [ 0 ] }
+		 *        ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using `columns`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columns": [
+		 *          { "class": "my_class" },
+		 *          null,
+		 *          null,
+		 *          null,
+		 *          null
+		 *        ]
+		 *      } );
+		 *    } );
+		 */
+		"sClass": "",
+	
+		/**
+		 * When DataTables calculates the column widths to assign to each column,
+		 * it finds the longest string in each column and then constructs a
+		 * temporary table and reads the widths from that. The problem with this
+		 * is that "mmm" is much wider then "iiii", but the latter is a longer
+		 * string - thus the calculation can go wrong (doing it properly and putting
+		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
+		 * a "work around" we provide this option. It will append its value to the
+		 * text that is found to be the longest string for the column - i.e. padding.
+		 * Generally you shouldn't need this!
+		 *  @type string
+		 *  @default <i>Empty string<i>
+		 *
+		 *  @name DataTable.defaults.column.contentPadding
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Using `columns`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columns": [
+		 *          null,
+		 *          null,
+		 *          null,
+		 *          {
+		 *            "contentPadding": "mmm"
+		 *          }
+		 *        ]
+		 *      } );
+		 *    } );
+		 */
+		"sContentPadding": "",
+	
+	
+		/**
+		 * Allows a default value to be given for a column's data, and will be used
+		 * whenever a null data source is encountered (this can be because `data`
+		 * is set to null, or because the data source itself is null).
+		 *  @type string
+		 *  @default null
+		 *
+		 *  @name DataTable.defaults.column.defaultContent
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Using `columnDefs`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [
+		 *          {
+		 *            "data": null,
+		 *            "defaultContent": "Edit",
+		 *            "targets": [ -1 ]
+		 *          }
+		 *        ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using `columns`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columns": [
+		 *          null,
+		 *          null,
+		 *          null,
+		 *          {
+		 *            "data": null,
+		 *            "defaultContent": "Edit"
+		 *          }
+		 *        ]
+		 *      } );
+		 *    } );
+		 */
+		"sDefaultContent": null,
+	
+	
+		/**
+		 * This parameter is only used in DataTables' server-side processing. It can
+		 * be exceptionally useful to know what columns are being displayed on the
+		 * client side, and to map these to database fields. When defined, the names
+		 * also allow DataTables to reorder information from the server if it comes
+		 * back in an unexpected order (i.e. if you switch your columns around on the
+		 * client-side, your server-side code does not also need updating).
+		 *  @type string
+		 *  @default <i>Empty string</i>
+		 *
+		 *  @name DataTable.defaults.column.name
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Using `columnDefs`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [
+		 *          { "name": "engine", "targets": [ 0 ] },
+		 *          { "name": "browser", "targets": [ 1 ] },
+		 *          { "name": "platform", "targets": [ 2 ] },
+		 *          { "name": "version", "targets": [ 3 ] },
+		 *          { "name": "grade", "targets": [ 4 ] }
+		 *        ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using `columns`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columns": [
+		 *          { "name": "engine" },
+		 *          { "name": "browser" },
+		 *          { "name": "platform" },
+		 *          { "name": "version" },
+		 *          { "name": "grade" }
+		 *        ]
+		 *      } );
+		 *    } );
+		 */
+		"sName": "",
+	
+	
+		/**
+		 * Defines a data source type for the ordering which can be used to read
+		 * real-time information from the table (updating the internally cached
+		 * version) prior to ordering. This allows ordering to occur on user
+		 * editable elements such as form inputs.
+		 *  @type string
+		 *  @default std
+		 *
+		 *  @name DataTable.defaults.column.orderDataType
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Using `columnDefs`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [
+		 *          { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
+		 *          { "type": "numeric", "targets": [ 3 ] },
+		 *          { "orderDataType": "dom-select", "targets": [ 4 ] },
+		 *          { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
+		 *        ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using `columns`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columns": [
+		 *          null,
+		 *          null,
+		 *          { "orderDataType": "dom-text" },
+		 *          { "orderDataType": "dom-text", "type": "numeric" },
+		 *          { "orderDataType": "dom-select" },
+		 *          { "orderDataType": "dom-checkbox" }
+		 *        ]
+		 *      } );
+		 *    } );
+		 */
+		"sSortDataType": "std",
+	
+	
+		/**
+		 * The title of this column.
+		 *  @type string
+		 *  @default null <i>Derived from the 'TH' value for this column in the
+		 *    original HTML table.</i>
+		 *
+		 *  @name DataTable.defaults.column.title
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Using `columnDefs`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [
+		 *          { "title": "My column title", "targets": [ 0 ] }
+		 *        ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using `columns`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columns": [
+		 *          { "title": "My column title" },
+		 *          null,
+		 *          null,
+		 *          null,
+		 *          null
+		 *        ]
+		 *      } );
+		 *    } );
+		 */
+		"sTitle": null,
+	
+	
+		/**
+		 * The type allows you to specify how the data for this column will be
+		 * ordered. Four types (string, numeric, date and html (which will strip
+		 * HTML tags before ordering)) are currently available. Note that only date
+		 * formats understood by Javascript's Date() object will be accepted as type
+		 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
+		 * 'numeric', 'date' or 'html' (by default). Further types can be adding
+		 * through plug-ins.
+		 *  @type string
+		 *  @default null <i>Auto-detected from raw data</i>
+		 *
+		 *  @name DataTable.defaults.column.type
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Using `columnDefs`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [
+		 *          { "type": "html", "targets": [ 0 ] }
+		 *        ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using `columns`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columns": [
+		 *          { "type": "html" },
+		 *          null,
+		 *          null,
+		 *          null,
+		 *          null
+		 *        ]
+		 *      } );
+		 *    } );
+		 */
+		"sType": null,
+	
+	
+		/**
+		 * Defining the width of the column, this parameter may take any CSS value
+		 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
+		 * been given a specific width through this interface ensuring that the table
+		 * remains readable.
+		 *  @type string
+		 *  @default null <i>Automatic</i>
+		 *
+		 *  @name DataTable.defaults.column.width
+		 *  @dtopt Columns
+		 *
+		 *  @example
+		 *    // Using `columnDefs`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columnDefs": [
+		 *          { "width": "20%", "targets": [ 0 ] }
+		 *        ]
+		 *      } );
+		 *    } );
+		 *
+		 *  @example
+		 *    // Using `columns`
+		 *    $(document).ready( function() {
+		 *      $('#example').dataTable( {
+		 *        "columns": [
+		 *          { "width": "20%" },
+		 *          null,
+		 *          null,
+		 *          null,
+		 *          null
+		 *        ]
+		 *      } );
+		 *    } );
+		 */
+		"sWidth": null
+	};
+	
+	_fnHungarianMap( DataTable.defaults.column );
+	
+	
+	
+	/**
+	 * DataTables settings object - this holds all the information needed for a
+	 * given table, including configuration, data and current application of the
+	 * table options. DataTables does not have a single instance for each DataTable
+	 * with the settings attached to that instance, but rather instances of the
+	 * DataTable "class" are created on-the-fly as needed (typically by a
+	 * $().dataTable() call) and the settings object is then applied to that
+	 * instance.
+	 *
+	 * Note that this object is related to {@link DataTable.defaults} but this
+	 * one is the internal data store for DataTables's cache of columns. It should
+	 * NOT be manipulated outside of DataTables. Any configuration should be done
+	 * through the initialisation options.
+	 *  @namespace
+	 *  @todo Really should attach the settings object to individual instances so we
+	 *    don't need to create new instances on each $().dataTable() call (if the
+	 *    table already exists). It would also save passing oSettings around and
+	 *    into every single function. However, this is a very significant
+	 *    architecture change for DataTables and will almost certainly break
+	 *    backwards compatibility with older installations. This is something that
+	 *    will be done in 2.0.
+	 */
+	DataTable.models.oSettings = {
+		/**
+		 * Primary features of DataTables and their enablement state.
+		 *  @namespace
+		 */
+		"oFeatures": {
+	
+			/**
+			 * Flag to say if DataTables should automatically try to calculate the
+			 * optimum table and columns widths (true) or not (false).
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type boolean
+			 */
+			"bAutoWidth": null,
+	
+			/**
+			 * Delay the creation of TR and TD elements until they are actually
+			 * needed by a driven page draw. This can give a significant speed
+			 * increase for Ajax source and Javascript source data, but makes no
+			 * difference at all fro DOM and server-side processing tables.
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type boolean
+			 */
+			"bDeferRender": null,
+	
+			/**
+			 * Enable filtering on the table or not. Note that if this is disabled
+			 * then there is no filtering at all on the table, including fnFilter.
+			 * To just remove the filtering input use sDom and remove the 'f' option.
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type boolean
+			 */
+			"bFilter": null,
+	
+			/**
+			 * Table information element (the 'Showing x of y records' div) enable
+			 * flag.
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type boolean
+			 */
+			"bInfo": null,
+	
+			/**
+			 * Present a user control allowing the end user to change the page size
+			 * when pagination is enabled.
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type boolean
+			 */
+			"bLengthChange": null,
+	
+			/**
+			 * Pagination enabled or not. Note that if this is disabled then length
+			 * changing must also be disabled.
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type boolean
+			 */
+			"bPaginate": null,
+	
+			/**
+			 * Processing indicator enable flag whenever DataTables is enacting a
+			 * user request - typically an Ajax request for server-side processing.
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type boolean
+			 */
+			"bProcessing": null,
+	
+			/**
+			 * Server-side processing enabled flag - when enabled DataTables will
+			 * get all data from the server for every draw - there is no filtering,
+			 * sorting or paging done on the client-side.
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type boolean
+			 */
+			"bServerSide": null,
+	
+			/**
+			 * Sorting enablement flag.
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type boolean
+			 */
+			"bSort": null,
+	
+			/**
+			 * Multi-column sorting
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type boolean
+			 */
+			"bSortMulti": null,
+	
+			/**
+			 * Apply a class to the columns which are being sorted to provide a
+			 * visual highlight or not. This can slow things down when enabled since
+			 * there is a lot of DOM interaction.
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type boolean
+			 */
+			"bSortClasses": null,
+	
+			/**
+			 * State saving enablement flag.
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type boolean
+			 */
+			"bStateSave": null
+		},
+	
+	
+		/**
+		 * Scrolling settings for a table.
+		 *  @namespace
+		 */
+		"oScroll": {
+			/**
+			 * When the table is shorter in height than sScrollY, collapse the
+			 * table container down to the height of the table (when true).
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type boolean
+			 */
+			"bCollapse": null,
+	
+			/**
+			 * Width of the scrollbar for the web-browser's platform. Calculated
+			 * during table initialisation.
+			 *  @type int
+			 *  @default 0
+			 */
+			"iBarWidth": 0,
+	
+			/**
+			 * Viewport width for horizontal scrolling. Horizontal scrolling is
+			 * disabled if an empty string.
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type string
+			 */
+			"sX": null,
+	
+			/**
+			 * Width to expand the table to when using x-scrolling. Typically you
+			 * should not need to use this.
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type string
+			 *  @deprecated
+			 */
+			"sXInner": null,
+	
+			/**
+			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
+			 * if an empty string.
+			 * Note that this parameter will be set by the initialisation routine. To
+			 * set a default use {@link DataTable.defaults}.
+			 *  @type string
+			 */
+			"sY": null
+		},
+	
+		/**
+		 * Language information for the table.
+		 *  @namespace
+		 *  @extends DataTable.defaults.oLanguage
+		 */
+		"oLanguage": {
+			/**
+			 * Information callback function. See
+			 * {@link DataTable.defaults.fnInfoCallback}
+			 *  @type function
+			 *  @default null
+			 */
+			"fnInfoCallback": null
+		},
+	
+		/**
+		 * Browser support parameters
+		 *  @namespace
+		 */
+		"oBrowser": {
+			/**
+			 * Indicate if the browser incorrectly calculates width:100% inside a
+			 * scrolling element (IE6/7)
+			 *  @type boolean
+			 *  @default false
+			 */
+			"bScrollOversize": false,
+	
+			/**
+			 * Determine if the vertical scrollbar is on the right or left of the
+			 * scrolling container - needed for rtl language layout, although not
+			 * all browsers move the scrollbar (Safari).
+			 *  @type boolean
+			 *  @default false
+			 */
+			"bScrollbarLeft": false
+		},
+	
+	
+		"ajax": null,
+	
+	
+		/**
+		 * Array referencing the nodes which are used for the features. The
+		 * parameters of this object match what is allowed by sDom - i.e.
+		 *   <ul>
+		 *     <li>'l' - Length changing</li>
+		 *     <li>'f' - Filtering input</li>
+		 *     <li>'t' - The table!</li>
+		 *     <li>'i' - Information</li>
+		 *     <li>'p' - Pagination</li>
+		 *     <li>'r' - pRocessing</li>
+		 *   </ul>
+		 *  @type array
+		 *  @default []
+		 */
+		"aanFeatures": [],
+	
+		/**
+		 * Store data information - see {@link DataTable.models.oRow} for detailed
+		 * information.
+		 *  @type array
+		 *  @default []
+		 */
+		"aoData": [],
+	
+		/**
+		 * Array of indexes which are in the current display (after filtering etc)
+		 *  @type array
+		 *  @default []
+		 */
+		"aiDisplay": [],
+	
+		/**
+		 * Array of indexes for display - no filtering
+		 *  @type array
+		 *  @default []
+		 */
+		"aiDisplayMaster": [],
+	
+		/**
+		 * Store information about each column that is in use
+		 *  @type array
+		 *  @default []
+		 */
+		"aoColumns": [],
+	
+		/**
+		 * Store information about the table's header
+		 *  @type array
+		 *  @default []
+		 */
+		"aoHeader": [],
+	
+		/**
+		 * Store information about the table's footer
+		 *  @type array
+		 *  @default []
+		 */
+		"aoFooter": [],
+	
+		/**
+		 * Store the applied global search information in case we want to force a
+		 * research or compare the old search to a new one.
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @namespace
+		 *  @extends DataTable.models.oSearch
+		 */
+		"oPreviousSearch": {},
+	
+		/**
+		 * Store the applied search for each column - see
+		 * {@link DataTable.models.oSearch} for the format that is used for the
+		 * filtering information for each column.
+		 *  @type array
+		 *  @default []
+		 */
+		"aoPreSearchCols": [],
+	
+		/**
+		 * Sorting that is applied to the table. Note that the inner arrays are
+		 * used in the following manner:
+		 * <ul>
+		 *   <li>Index 0 - column number</li>
+		 *   <li>Index 1 - current sorting direction</li>
+		 * </ul>
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type array
+		 *  @todo These inner arrays should really be objects
+		 */
+		"aaSorting": null,
+	
+		/**
+		 * Sorting that is always applied to the table (i.e. prefixed in front of
+		 * aaSorting).
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type array
+		 *  @default []
+		 */
+		"aaSortingFixed": [],
+	
+		/**
+		 * Classes to use for the striping of a table.
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type array
+		 *  @default []
+		 */
+		"asStripeClasses": null,
+	
+		/**
+		 * If restoring a table - we should restore its striping classes as well
+		 *  @type array
+		 *  @default []
+		 */
+		"asDestroyStripes": [],
+	
+		/**
+		 * If restoring a table - we should restore its width
+		 *  @type int
+		 *  @default 0
+		 */
+		"sDestroyWidth": 0,
+	
+		/**
+		 * Callback functions array for every time a row is inserted (i.e. on a draw).
+		 *  @type array
+		 *  @default []
+		 */
+		"aoRowCallback": [],
+	
+		/**
+		 * Callback functions for the header on each draw.
+		 *  @type array
+		 *  @default []
+		 */
+		"aoHeaderCallback": [],
+	
+		/**
+		 * Callback function for the footer on each draw.
+		 *  @type array
+		 *  @default []
+		 */
+		"aoFooterCallback": [],
+	
+		/**
+		 * Array of callback functions for draw callback functions
+		 *  @type array
+		 *  @default []
+		 */
+		"aoDrawCallback": [],
+	
+		/**
+		 * Array of callback functions for row created function
+		 *  @type array
+		 *  @default []
+		 */
+		"aoRowCreatedCallback": [],
+	
+		/**
+		 * Callback functions for just before the table is redrawn. A return of
+		 * false will be used to cancel the draw.
+		 *  @type array
+		 *  @default []
+		 */
+		"aoPreDrawCallback": [],
+	
+		/**
+		 * Callback functions for when the table has been initialised.
+		 *  @type array
+		 *  @default []
+		 */
+		"aoInitComplete": [],
+	
+	
+		/**
+		 * Callbacks for modifying the settings to be stored for state saving, prior to
+		 * saving state.
+		 *  @type array
+		 *  @default []
+		 */
+		"aoStateSaveParams": [],
+	
+		/**
+		 * Callbacks for modifying the settings that have been stored for state saving
+		 * prior to using the stored values to restore the state.
+		 *  @type array
+		 *  @default []
+		 */
+		"aoStateLoadParams": [],
+	
+		/**
+		 * Callbacks for operating on the settings object once the saved state has been
+		 * loaded
+		 *  @type array
+		 *  @default []
+		 */
+		"aoStateLoaded": [],
+	
+		/**
+		 * Cache the table ID for quick access
+		 *  @type string
+		 *  @default <i>Empty string</i>
+		 */
+		"sTableId": "",
+	
+		/**
+		 * The TABLE node for the main table
+		 *  @type node
+		 *  @default null
+		 */
+		"nTable": null,
+	
+		/**
+		 * Permanent ref to the thead element
+		 *  @type node
+		 *  @default null
+		 */
+		"nTHead": null,
+	
+		/**
+		 * Permanent ref to the tfoot element - if it exists
+		 *  @type node
+		 *  @default null
+		 */
+		"nTFoot": null,
+	
+		/**
+		 * Permanent ref to the tbody element
+		 *  @type node
+		 *  @default null
+		 */
+		"nTBody": null,
+	
+		/**
+		 * Cache the wrapper node (contains all DataTables controlled elements)
+		 *  @type node
+		 *  @default null
+		 */
+		"nTableWrapper": null,
+	
+		/**
+		 * Indicate if when using server-side processing the loading of data
+		 * should be deferred until the second draw.
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type boolean
+		 *  @default false
+		 */
+		"bDeferLoading": false,
+	
+		/**
+		 * Indicate if all required information has been read in
+		 *  @type boolean
+		 *  @default false
+		 */
+		"bInitialised": false,
+	
+		/**
+		 * Information about open rows. Each object in the array has the parameters
+		 * 'nTr' and 'nParent'
+		 *  @type array
+		 *  @default []
+		 */
+		"aoOpenRows": [],
+	
+		/**
+		 * Dictate the positioning of DataTables' control elements - see
+		 * {@link DataTable.model.oInit.sDom}.
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type string
+		 *  @default null
+		 */
+		"sDom": null,
+	
+		/**
+		 * Search delay (in mS)
+		 *  @type integer
+		 *  @default null
+		 */
+		"searchDelay": null,
+	
+		/**
+		 * Which type of pagination should be used.
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type string
+		 *  @default two_button
+		 */
+		"sPaginationType": "two_button",
+	
+		/**
+		 * The state duration (for `stateSave`) in seconds.
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type int
+		 *  @default 0
+		 */
+		"iStateDuration": 0,
+	
+		/**
+		 * Array of callback functions for state saving. Each array element is an
+		 * object with the following parameters:
+		 *   <ul>
+		 *     <li>function:fn - function to call. Takes two parameters, oSettings
+		 *       and the JSON string to save that has been thus far created. Returns
+		 *       a JSON string to be inserted into a json object
+		 *       (i.e. '"param": [ 0, 1, 2]')</li>
+		 *     <li>string:sName - name of callback</li>
+		 *   </ul>
+		 *  @type array
+		 *  @default []
+		 */
+		"aoStateSave": [],
+	
+		/**
+		 * Array of callback functions for state loading. Each array element is an
+		 * object with the following parameters:
+		 *   <ul>
+		 *     <li>function:fn - function to call. Takes two parameters, oSettings
+		 *       and the object stored. May return false to cancel state loading</li>
+		 *     <li>string:sName - name of callback</li>
+		 *   </ul>
+		 *  @type array
+		 *  @default []
+		 */
+		"aoStateLoad": [],
+	
+		/**
+		 * State that was saved. Useful for back reference
+		 *  @type object
+		 *  @default null
+		 */
+		"oSavedState": null,
+	
+		/**
+		 * State that was loaded. Useful for back reference
+		 *  @type object
+		 *  @default null
+		 */
+		"oLoadedState": null,
+	
+		/**
+		 * Source url for AJAX data for the table.
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type string
+		 *  @default null
+		 */
+		"sAjaxSource": null,
+	
+		/**
+		 * Property from a given object from which to read the table data from. This
+		 * can be an empty string (when not server-side processing), in which case
+		 * it is  assumed an an array is given directly.
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type string
+		 */
+		"sAjaxDataProp": null,
+	
+		/**
+		 * Note if draw should be blocked while getting data
+		 *  @type boolean
+		 *  @default true
+		 */
+		"bAjaxDataGet": true,
+	
+		/**
+		 * The last jQuery XHR object that was used for server-side data gathering.
+		 * This can be used for working with the XHR information in one of the
+		 * callbacks
+		 *  @type object
+		 *  @default null
+		 */
+		"jqXHR": null,
+	
+		/**
+		 * JSON returned from the server in the last Ajax request
+		 *  @type object
+		 *  @default undefined
+		 */
+		"json": undefined,
+	
+		/**
+		 * Data submitted as part of the last Ajax request
+		 *  @type object
+		 *  @default undefined
+		 */
+		"oAjaxData": undefined,
+	
+		/**
+		 * Function to get the server-side data.
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type function
+		 */
+		"fnServerData": null,
+	
+		/**
+		 * Functions which are called prior to sending an Ajax request so extra
+		 * parameters can easily be sent to the server
+		 *  @type array
+		 *  @default []
+		 */
+		"aoServerParams": [],
+	
+		/**
+		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
+		 * required).
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type string
+		 */
+		"sServerMethod": null,
+	
+		/**
+		 * Format numbers for display.
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type function
+		 */
+		"fnFormatNumber": null,
+	
+		/**
+		 * List of options that can be used for the user selectable length menu.
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type array
+		 *  @default []
+		 */
+		"aLengthMenu": null,
+	
+		/**
+		 * Counter for the draws that the table does. Also used as a tracker for
+		 * server-side processing
+		 *  @type int
+		 *  @default 0
+		 */
+		"iDraw": 0,
+	
+		/**
+		 * Indicate if a redraw is being done - useful for Ajax
+		 *  @type boolean
+		 *  @default false
+		 */
+		"bDrawing": false,
+	
+		/**
+		 * Draw index (iDraw) of the last error when parsing the returned data
+		 *  @type int
+		 *  @default -1
+		 */
+		"iDrawError": -1,
+	
+		/**
+		 * Paging display length
+		 *  @type int
+		 *  @default 10
+		 */
+		"_iDisplayLength": 10,
+	
+		/**
+		 * Paging start point - aiDisplay index
+		 *  @type int
+		 *  @default 0
+		 */
+		"_iDisplayStart": 0,
+	
+		/**
+		 * Server-side processing - number of records in the result set
+		 * (i.e. before filtering), Use fnRecordsTotal rather than
+		 * this property to get the value of the number of records, regardless of
+		 * the server-side processing setting.
+		 *  @type int
+		 *  @default 0
+		 *  @private
+		 */
+		"_iRecordsTotal": 0,
+	
+		/**
+		 * Server-side processing - number of records in the current display set
+		 * (i.e. after filtering). Use fnRecordsDisplay rather than
+		 * this property to get the value of the number of records, regardless of
+		 * the server-side processing setting.
+		 *  @type boolean
+		 *  @default 0
+		 *  @private
+		 */
+		"_iRecordsDisplay": 0,
+	
+		/**
+		 * Flag to indicate if jQuery UI marking and classes should be used.
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type boolean
+		 */
+		"bJUI": null,
+	
+		/**
+		 * The classes to use for the table
+		 *  @type object
+		 *  @default {}
+		 */
+		"oClasses": {},
+	
+		/**
+		 * Flag attached to the settings object so you can check in the draw
+		 * callback if filtering has been done in the draw. Deprecated in favour of
+		 * events.
+		 *  @type boolean
+		 *  @default false
+		 *  @deprecated
+		 */
+		"bFiltered": false,
+	
+		/**
+		 * Flag attached to the settings object so you can check in the draw
+		 * callback if sorting has been done in the draw. Deprecated in favour of
+		 * events.
+		 *  @type boolean
+		 *  @default false
+		 *  @deprecated
+		 */
+		"bSorted": false,
+	
+		/**
+		 * Indicate that if multiple rows are in the header and there is more than
+		 * one unique cell per column, if the top one (true) or bottom one (false)
+		 * should be used for sorting / title by DataTables.
+		 * Note that this parameter will be set by the initialisation routine. To
+		 * set a default use {@link DataTable.defaults}.
+		 *  @type boolean
+		 */
+		"bSortCellsTop": null,
+	
+		/**
+		 * Initialisation object that is used for the table
+		 *  @type object
+		 *  @default null
+		 */
+		"oInit": null,
+	
+		/**
+		 * Destroy callback functions - for plug-ins to attach themselves to the
+		 * destroy so they can clean up markup and events.
+		 *  @type array
+		 *  @default []
+		 */
+		"aoDestroyCallback": [],
+	
+	
+		/**
+		 * Get the number of records in the current record set, before filtering
+		 *  @type function
+		 */
+		"fnRecordsTotal": function ()
+		{
+			return _fnDataSource( this ) == 'ssp' ?
+				this._iRecordsTotal * 1 :
+				this.aiDisplayMaster.length;
+		},
+	
+		/**
+		 * Get the number of records in the current record set, after filtering
+		 *  @type function
+		 */
+		"fnRecordsDisplay": function ()
+		{
+			return _fnDataSource( this ) == 'ssp' ?
+				this._iRecordsDisplay * 1 :
+				this.aiDisplay.length;
+		},
+	
+		/**
+		 * Get the display end point - aiDisplay index
+		 *  @type function
+		 */
+		"fnDisplayEnd": function ()
+		{
+			var
+				len      = this._iDisplayLength,
+				start    = this._iDisplayStart,
+				calc     = start + len,
+				records  = this.aiDisplay.length,
+				features = this.oFeatures,
+				paginate = features.bPaginate;
+	
+			if ( features.bServerSide ) {
+				return paginate === false || len === -1 ?
+					start + records :
+					Math.min( start+len, this._iRecordsDisplay );
+			}
+			else {
+				return ! paginate || calc>records || len===-1 ?
+					records :
+					calc;
+			}
+		},
+	
+		/**
+		 * The DataTables object for this table
+		 *  @type object
+		 *  @default null
+		 */
+		"oInstance": null,
+	
+		/**
+		 * Unique identifier for each instance of the DataTables object. If there
+		 * is an ID on the table node, then it takes that value, otherwise an
+		 * incrementing internal counter is used.
+		 *  @type string
+		 *  @default null
+		 */
+		"sInstance": null,
+	
+		/**
+		 * tabindex attribute value that is added to DataTables control elements, allowing
+		 * keyboard navigation of the table and its controls.
+		 */
+		"iTabIndex": 0,
+	
+		/**
+		 * DIV container for the footer scrolling table if scrolling
+		 */
+		"nScrollHead": null,
+	
+		/**
+		 * DIV container for the footer scrolling table if scrolling
+		 */
+		"nScrollFoot": null,
+	
+		/**
+		 * Last applied sort
+		 *  @type array
+		 *  @default []
+		 */
+		"aLastSort": [],
+	
+		/**
+		 * Stored plug-in instances
+		 *  @type object
+		 *  @default {}
+		 */
+		"oPlugins": {}
+	};
+
+	/**
+	 * Extension object for DataTables that is used to provide all extension
+	 * options.
+	 *
+	 * Note that the `DataTable.ext` object is available through
+	 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
+	 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
+	 *  @namespace
+	 *  @extends DataTable.models.ext
+	 */
+	
+	
+	/**
+	 * DataTables extensions
+	 * 
+	 * This namespace acts as a collection area for plug-ins that can be used to
+	 * extend DataTables capabilities. Indeed many of the build in methods
+	 * use this method to provide their own capabilities (sorting methods for
+	 * example).
+	 *
+	 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
+	 * reasons
+	 *
+	 *  @namespace
+	 */
+	DataTable.ext = _ext = {
+		/**
+		 * Buttons. For use with the Buttons extension for DataTables. This is
+		 * defined here so other extensions can define buttons regardless of load
+		 * order. It is _not_ used by DataTables core.
+		 *
+		 *  @type object
+		 *  @default {}
+		 */
+		buttons: {},
+	
+	
+		/**
+		 * Element class names
+		 *
+		 *  @type object
+		 *  @default {}
+		 */
+		classes: {},
+	
+	
+		/**
+		 * Error reporting.
+		 * 
+		 * How should DataTables report an error. Can take the value 'alert',
+		 * 'throw', 'none' or a function.
+		 *
+		 *  @type string|function
+		 *  @default alert
+		 */
+		errMode: "alert",
+	
+	
+		/**
+		 * Feature plug-ins.
+		 * 
+		 * This is an array of objects which describe the feature plug-ins that are
+		 * available to DataTables. These feature plug-ins are then available for
+		 * use through the `dom` initialisation option.
+		 * 
+		 * Each feature plug-in is described by an object which must have the
+		 * following properties:
+		 * 
+		 * * `fnInit` - function that is used to initialise the plug-in,
+		 * * `cFeature` - a character so the feature can be enabled by the `dom`
+		 *   instillation option. This is case sensitive.
+		 *
+		 * The `fnInit` function has the following input parameters:
+		 *
+		 * 1. `{object}` DataTables settings object: see
+		 *    {@link DataTable.models.oSettings}
+		 *
+		 * And the following return is expected:
+		 * 
+		 * * {node|null} The element which contains your feature. Note that the
+		 *   return may also be void if your plug-in does not require to inject any
+		 *   DOM elements into DataTables control (`dom`) - for example this might
+		 *   be useful when developing a plug-in which allows table control via
+		 *   keyboard entry
+		 *
+		 *  @type array
+		 *
+		 *  @example
+		 *    $.fn.dataTable.ext.features.push( {
+		 *      "fnInit": function( oSettings ) {
+		 *        return new TableTools( { "oDTSettings": oSettings } );
+		 *      },
+		 *      "cFeature": "T"
+		 *    } );
+		 */
+		feature: [],
+	
+	
+		/**
+		 * Row searching.
+		 * 
+		 * This method of searching is complimentary to the default type based
+		 * searching, and a lot more comprehensive as it allows you complete control
+		 * over the searching logic. Each element in this array is a function
+		 * (parameters described below) that is called for every row in the table,
+		 * and your logic decides if it should be included in the searching data set
+		 * or not.
+		 *
+		 * Searching functions have the following input parameters:
+		 *
+		 * 1. `{object}` DataTables settings object: see
+		 *    {@link DataTable.models.oSettings}
+		 * 2. `{array|object}` Data for the row to be processed (same as the
+		 *    original format that was passed in as the data source, or an array
+		 *    from a DOM data source
+		 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
+		 *    can be useful to retrieve the `TR` element if you need DOM interaction.
+		 *
+		 * And the following return is expected:
+		 *
+		 * * {boolean} Include the row in the searched result set (true) or not
+		 *   (false)
+		 *
+		 * Note that as with the main search ability in DataTables, technically this
+		 * is "filtering", since it is subtractive. However, for consistency in
+		 * naming we call it searching here.
+		 *
+		 *  @type array
+		 *  @default []
+		 *
+		 *  @example
+		 *    // The following example shows custom search being applied to the
+		 *    // fourth column (i.e. the data[3] index) based on two input values
+		 *    // from the end-user, matching the data in a certain range.
+		 *    $.fn.dataTable.ext.search.push(
+		 *      function( settings, data, dataIndex ) {
+		 *        var min = document.getElementById('min').value * 1;
+		 *        var max = document.getElementById('max').value * 1;
+		 *        var version = data[3] == "-" ? 0 : data[3]*1;
+		 *
+		 *        if ( min == "" && max == "" ) {
+		 *          return true;
+		 *        }
+		 *        else if ( min == "" && version < max ) {
+		 *          return true;
+		 *        }
+		 *        else if ( min < version && "" == max ) {
+		 *          return true;
+		 *        }
+		 *        else if ( min < version && version < max ) {
+		 *          return true;
+		 *        }
+		 *        return false;
+		 *      }
+		 *    );
+		 */
+		search: [],
+	
+	
+		/**
+		 * Selector extensions
+		 *
+		 * The `selector` option can be used to extend the options available for the
+		 * selector modifier options (`selector-modifier` object data type) that
+		 * each of the three built in selector types offer (row, column and cell +
+		 * their plural counterparts). For example the Select extension uses this
+		 * mechanism to provide an option to select only rows, columns and cells
+		 * that have been marked as selected by the end user (`{selected: true}`),
+		 * which can be used in conjunction with the existing built in selector
+		 * options.
+		 *
+		 * Each property is an array to which functions can be pushed. The functions
+		 * take three attributes:
+		 *
+		 * * Settings object for the host table
+		 * * Options object (`selector-modifier` object type)
+		 * * Array of selected item indexes
+		 *
+		 * The return is an array of the resulting item indexes after the custom
+		 * selector has been applied.
+		 *
+		 *  @type object
+		 */
+		selector: {
+			cell: [],
+			column: [],
+			row: []
+		},
+	
+	
+		/**
+		 * Internal functions, exposed for used in plug-ins.
+		 * 
+		 * Please note that you should not need to use the internal methods for
+		 * anything other than a plug-in (and even then, try to avoid if possible).
+		 * The internal function may change between releases.
+		 *
+		 *  @type object
+		 *  @default {}
+		 */
+		internal: {},
+	
+	
+		/**
+		 * Legacy configuration options. Enable and disable legacy options that
+		 * are available in DataTables.
+		 *
+		 *  @type object
+		 */
+		legacy: {
+			/**
+			 * Enable / disable DataTables 1.9 compatible server-side processing
+			 * requests
+			 *
+			 *  @type boolean
+			 *  @default null
+			 */
+			ajax: null
+		},
+	
+	
+		/**
+		 * Pagination plug-in methods.
+		 * 
+		 * Each entry in this object is a function and defines which buttons should
+		 * be shown by the pagination rendering method that is used for the table:
+		 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
+		 * buttons are displayed in the document, while the functions here tell it
+		 * what buttons to display. This is done by returning an array of button
+		 * descriptions (what each button will do).
+		 *
+		 * Pagination types (the four built in options and any additional plug-in
+		 * options defined here) can be used through the `paginationType`
+		 * initialisation parameter.
+		 *
+		 * The functions defined take two parameters:
+		 *
+		 * 1. `{int} page` The current page index
+		 * 2. `{int} pages` The number of pages in the table
+		 *
+		 * Each function is expected to return an array where each element of the
+		 * array can be one of:
+		 *
+		 * * `first` - Jump to first page when activated
+		 * * `last` - Jump to last page when activated
+		 * * `previous` - Show previous page when activated
+		 * * `next` - Show next page when activated
+		 * * `{int}` - Show page of the index given
+		 * * `{array}` - A nested array containing the above elements to add a
+		 *   containing 'DIV' element (might be useful for styling).
+		 *
+		 * Note that DataTables v1.9- used this object slightly differently whereby
+		 * an object with two functions would be defined for each plug-in. That
+		 * ability is still supported by DataTables 1.10+ to provide backwards
+		 * compatibility, but this option of use is now decremented and no longer
+		 * documented in DataTables 1.10+.
+		 *
+		 *  @type object
+		 *  @default {}
+		 *
+		 *  @example
+		 *    // Show previous, next and current page buttons only
+		 *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
+		 *      return [ 'previous', page, 'next' ];
+		 *    };
+		 */
+		pager: {},
+	
+	
+		renderer: {
+			pageButton: {},
+			header: {}
+		},
+	
+	
+		/**
+		 * Ordering plug-ins - custom data source
+		 * 
+		 * The extension options for ordering of data available here is complimentary
+		 * to the default type based ordering that DataTables typically uses. It
+		 * allows much greater control over the the data that is being used to
+		 * order a column, but is necessarily therefore more complex.
+		 * 
+		 * This type of ordering is useful if you want to do ordering based on data
+		 * live from the DOM (for example the contents of an 'input' element) rather
+		 * than just the static string that DataTables knows of.
+		 * 
+		 * The way these plug-ins work is that you create an array of the values you
+		 * wish to be ordering for the column in question and then return that
+		 * array. The data in the array much be in the index order of the rows in
+		 * the table (not the currently ordering order!). Which order data gathering
+		 * function is run here depends on the `dt-init columns.orderDataType`
+		 * parameter that is used for the column (if any).
+		 *
+		 * The functions defined take two parameters:
+		 *
+		 * 1. `{object}` DataTables settings object: see
+		 *    {@link DataTable.models.oSettings}
+		 * 2. `{int}` Target column index
+		 *
+		 * Each function is expected to return an array:
+		 *
+		 * * `{array}` Data for the column to be ordering upon
+		 *
+		 *  @type array
+		 *
+		 *  @example
+		 *    // Ordering using `input` node values
+		 *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
+		 *    {
+		 *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
+		 *        return $('input', td).val();
+		 *      } );
+		 *    }
+		 */
+		order: {},
+	
+	
+		/**
+		 * Type based plug-ins.
+		 *
+		 * Each column in DataTables has a type assigned to it, either by automatic
+		 * detection or by direct assignment using the `type` option for the column.
+		 * The type of a column will effect how it is ordering and search (plug-ins
+		 * can also make use of the column type if required).
+		 *
+		 * @namespace
+		 */
+		type: {
+			/**
+			 * Type detection functions.
+			 *
+			 * The functions defined in this object are used to automatically detect
+			 * a column's type, making initialisation of DataTables super easy, even
+			 * when complex data is in the table.
+			 *
+			 * The functions defined take two parameters:
+			 *
+		     *  1. `{*}` Data from the column cell to be analysed
+		     *  2. `{settings}` DataTables settings object. This can be used to
+		     *     perform context specific type detection - for example detection
+		     *     based on language settings such as using a comma for a decimal
+		     *     place. Generally speaking the options from the settings will not
+		     *     be required
+			 *
+			 * Each function is expected to return:
+			 *
+			 * * `{string|null}` Data type detected, or null if unknown (and thus
+			 *   pass it on to the other type detection functions.
+			 *
+			 *  @type array
+			 *
+			 *  @example
+			 *    // Currency type detection plug-in:
+			 *    $.fn.dataTable.ext.type.detect.push(
+			 *      function ( data, settings ) {
+			 *        // Check the numeric part
+			 *        if ( ! $.isNumeric( data.substring(1) ) ) {
+			 *          return null;
+			 *        }
+			 *
+			 *        // Check prefixed by currency
+			 *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
+			 *          return 'currency';
+			 *        }
+			 *        return null;
+			 *      }
+			 *    );
+			 */
+			detect: [],
+	
+	
+			/**
+			 * Type based search formatting.
+			 *
+			 * The type based searching functions can be used to pre-format the
+			 * data to be search on. For example, it can be used to strip HTML
+			 * tags or to de-format telephone numbers for numeric only searching.
+			 *
+			 * Note that is a search is not defined for a column of a given type,
+			 * no search formatting will be performed.
+			 * 
+			 * Pre-processing of searching data plug-ins - When you assign the sType
+			 * for a column (or have it automatically detected for you by DataTables
+			 * or a type detection plug-in), you will typically be using this for
+			 * custom sorting, but it can also be used to provide custom searching
+			 * by allowing you to pre-processing the data and returning the data in
+			 * the format that should be searched upon. This is done by adding
+			 * functions this object with a parameter name which matches the sType
+			 * for that target column. This is the corollary of <i>afnSortData</i>
+			 * for searching data.
+			 *
+			 * The functions defined take a single parameter:
+			 *
+		     *  1. `{*}` Data from the column cell to be prepared for searching
+			 *
+			 * Each function is expected to return:
+			 *
+			 * * `{string|null}` Formatted string that will be used for the searching.
+			 *
+			 *  @type object
+			 *  @default {}
+			 *
+			 *  @example
+			 *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
+			 *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
+			 *    }
+			 */
+			search: {},
+	
+	
+			/**
+			 * Type based ordering.
+			 *
+			 * The column type tells DataTables what ordering to apply to the table
+			 * when a column is sorted upon. The order for each type that is defined,
+			 * is defined by the functions available in this object.
+			 *
+			 * Each ordering option can be described by three properties added to
+			 * this object:
+			 *
+			 * * `{type}-pre` - Pre-formatting function
+			 * * `{type}-asc` - Ascending order function
+			 * * `{type}-desc` - Descending order function
+			 *
+			 * All three can be used together, only `{type}-pre` or only
+			 * `{type}-asc` and `{type}-desc` together. It is generally recommended
+			 * that only `{type}-pre` is used, as this provides the optimal
+			 * implementation in terms of speed, although the others are provided
+			 * for compatibility with existing Javascript sort functions.
+			 *
+			 * `{type}-pre`: Functions defined take a single parameter:
+			 *
+		     *  1. `{*}` Data from the column cell to be prepared for ordering
+			 *
+			 * And return:
+			 *
+			 * * `{*}` Data to be sorted upon
+			 *
+			 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
+			 * functions, taking two parameters:
+			 *
+		     *  1. `{*}` Data to compare to the second parameter
+		     *  2. `{*}` Data to compare to the first parameter
+			 *
+			 * And returning:
+			 *
+			 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
+			 *   than the second parameter, ===0 if the two parameters are equal and
+			 *   >0 if the first parameter should be sorted height than the second
+			 *   parameter.
+			 * 
+			 *  @type object
+			 *  @default {}
+			 *
+			 *  @example
+			 *    // Numeric ordering of formatted numbers with a pre-formatter
+			 *    $.extend( $.fn.dataTable.ext.type.order, {
+			 *      "string-pre": function(x) {
+			 *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
+			 *        return parseFloat( a );
+			 *      }
+			 *    } );
+			 *
+			 *  @example
+			 *    // Case-sensitive string ordering, with no pre-formatting method
+			 *    $.extend( $.fn.dataTable.ext.order, {
+			 *      "string-case-asc": function(x,y) {
+			 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+			 *      },
+			 *      "string-case-desc": function(x,y) {
+			 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+			 *      }
+			 *    } );
+			 */
+			order: {}
+		},
+	
+		/**
+		 * Unique DataTables instance counter
+		 *
+		 * @type int
+		 * @private
+		 */
+		_unique: 0,
+	
+	
+		//
+		// Depreciated
+		// The following properties are retained for backwards compatiblity only.
+		// The should not be used in new projects and will be removed in a future
+		// version
+		//
+	
+		/**
+		 * Version check function.
+		 *  @type function
+		 *  @depreciated Since 1.10
+		 */
+		fnVersionCheck: DataTable.fnVersionCheck,
+	
+	
+		/**
+		 * Index for what 'this' index API functions should use
+		 *  @type int
+		 *  @deprecated Since v1.10
+		 */
+		iApiIndex: 0,
+	
+	
+		/**
+		 * jQuery UI class container
+		 *  @type object
+		 *  @deprecated Since v1.10
+		 */
+		oJUIClasses: {},
+	
+	
+		/**
+		 * Software version
+		 *  @type string
+		 *  @deprecated Since v1.10
+		 */
+		sVersion: DataTable.version
+	};
+	
+	
+	//
+	// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
+	//
+	$.extend( _ext, {
+		afnFiltering: _ext.search,
+		aTypes:       _ext.type.detect,
+		ofnSearch:    _ext.type.search,
+		oSort:        _ext.type.order,
+		afnSortData:  _ext.order,
+		aoFeatures:   _ext.feature,
+		oApi:         _ext.internal,
+		oStdClasses:  _ext.classes,
+		oPagination:  _ext.pager
+	} );
+	
+	
+	$.extend( DataTable.ext.classes, {
+		"sTable": "dataTable",
+		"sNoFooter": "no-footer",
+	
+		/* Paging buttons */
+		"sPageButton": "paginate_button",
+		"sPageButtonActive": "current",
+		"sPageButtonDisabled": "disabled",
+	
+		/* Striping classes */
+		"sStripeOdd": "odd",
+		"sStripeEven": "even",
+	
+		/* Empty row */
+		"sRowEmpty": "dataTables_empty",
+	
+		/* Features */
+		"sWrapper": "dataTables_wrapper",
+		"sFilter": "dataTables_filter",
+		"sInfo": "dataTables_info",
+		"sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
+		"sLength": "dataTables_length",
+		"sProcessing": "dataTables_processing",
+	
+		/* Sorting */
+		"sSortAsc": "sorting_asc",
+		"sSortDesc": "sorting_desc",
+		"sSortable": "sorting", /* Sortable in both directions */
+		"sSortableAsc": "sorting_asc_disabled",
+		"sSortableDesc": "sorting_desc_disabled",
+		"sSortableNone": "sorting_disabled",
+		"sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
+	
+		/* Filtering */
+		"sFilterInput": "",
+	
+		/* Page length */
+		"sLengthSelect": "",
+	
+		/* Scrolling */
+		"sScrollWrapper": "dataTables_scroll",
+		"sScrollHead": "dataTables_scrollHead",
+		"sScrollHeadInner": "dataTables_scrollHeadInner",
+		"sScrollBody": "dataTables_scrollBody",
+		"sScrollFoot": "dataTables_scrollFoot",
+		"sScrollFootInner": "dataTables_scrollFootInner",
+	
+		/* Misc */
+		"sHeaderTH": "",
+		"sFooterTH": "",
+	
+		// Deprecated
+		"sSortJUIAsc": "",
+		"sSortJUIDesc": "",
+		"sSortJUI": "",
+		"sSortJUIAscAllowed": "",
+		"sSortJUIDescAllowed": "",
+		"sSortJUIWrapper": "",
+		"sSortIcon": "",
+		"sJUIHeader": "",
+		"sJUIFooter": ""
+	} );
+	
+	
+	(function() {
+	
+	// Reused strings for better compression. Closure compiler appears to have a
+	// weird edge case where it is trying to expand strings rather than use the
+	// variable version. This results in about 200 bytes being added, for very
+	// little preference benefit since it this run on script load only.
+	var _empty = '';
+	_empty = '';
+	
+	var _stateDefault = _empty + 'ui-state-default';
+	var _sortIcon     = _empty + 'css_right ui-icon ui-icon-';
+	var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
+	
+	$.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {
+		/* Full numbers paging buttons */
+		"sPageButton":         "fg-button ui-button "+_stateDefault,
+		"sPageButtonActive":   "ui-state-disabled",
+		"sPageButtonDisabled": "ui-state-disabled",
+	
+		/* Features */
+		"sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
+			"ui-buttonset-multi paging_", /* Note that the type is postfixed */
+	
+		/* Sorting */
+		"sSortAsc":            _stateDefault+" sorting_asc",
+		"sSortDesc":           _stateDefault+" sorting_desc",
+		"sSortable":           _stateDefault+" sorting",
+		"sSortableAsc":        _stateDefault+" sorting_asc_disabled",
+		"sSortableDesc":       _stateDefault+" sorting_desc_disabled",
+		"sSortableNone":       _stateDefault+" sorting_disabled",
+		"sSortJUIAsc":         _sortIcon+"triangle-1-n",
+		"sSortJUIDesc":        _sortIcon+"triangle-1-s",
+		"sSortJUI":            _sortIcon+"carat-2-n-s",
+		"sSortJUIAscAllowed":  _sortIcon+"carat-1-n",
+		"sSortJUIDescAllowed": _sortIcon+"carat-1-s",
+		"sSortJUIWrapper":     "DataTables_sort_wrapper",
+		"sSortIcon":           "DataTables_sort_icon",
+	
+		/* Scrolling */
+		"sScrollHead": "dataTables_scrollHead "+_stateDefault,
+		"sScrollFoot": "dataTables_scrollFoot "+_stateDefault,
+	
+		/* Misc */
+		"sHeaderTH":  _stateDefault,
+		"sFooterTH":  _stateDefault,
+		"sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr",
+		"sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br"
+	} );
+	
+	}());
+	
+	
+	
+	var extPagination = DataTable.ext.pager;
+	
+	function _numbers ( page, pages ) {
+		var
+			numbers = [],
+			buttons = extPagination.numbers_length,
+			half = Math.floor( buttons / 2 ),
+			i = 1;
+	
+		if ( pages <= buttons ) {
+			numbers = _range( 0, pages );
+		}
+		else if ( page <= half ) {
+			numbers = _range( 0, buttons-2 );
+			numbers.push( 'ellipsis' );
+			numbers.push( pages-1 );
+		}
+		else if ( page >= pages - 1 - half ) {
+			numbers = _range( pages-(buttons-2), pages );
+			numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
+			numbers.splice( 0, 0, 0 );
+		}
+		else {
+			numbers = _range( page-half+2, page+half-1 );
+			numbers.push( 'ellipsis' );
+			numbers.push( pages-1 );
+			numbers.splice( 0, 0, 'ellipsis' );
+			numbers.splice( 0, 0, 0 );
+		}
+	
+		numbers.DT_el = 'span';
+		return numbers;
+	}
+	
+	
+	$.extend( extPagination, {
+		simple: function ( page, pages ) {
+			return [ 'previous', 'next' ];
+		},
+	
+		full: function ( page, pages ) {
+			return [  'first', 'previous', 'next', 'last' ];
+		},
+	
+		simple_numbers: function ( page, pages ) {
+			return [ 'previous', _numbers(page, pages), 'next' ];
+		},
+	
+		full_numbers: function ( page, pages ) {
+			return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
+		},
+	
+		// For testing and plug-ins to use
+		_numbers: _numbers,
+	
+		// Number of number buttons (including ellipsis) to show. _Must be odd!_
+		numbers_length: 7
+	} );
+	
+	
+	$.extend( true, DataTable.ext.renderer, {
+		pageButton: {
+			_: function ( settings, host, idx, buttons, page, pages ) {
+				var classes = settings.oClasses;
+				var lang = settings.oLanguage.oPaginate;
+				var btnDisplay, btnClass, counter=0;
+	
+				var attach = function( container, buttons ) {
+					var i, ien, node, button;
+					var clickHandler = function ( e ) {
+						_fnPageChange( settings, e.data.action, true );
+					};
+	
+					for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
+						button = buttons[i];
+	
+						if ( $.isArray( button ) ) {
+							var inner = $( '<'+(button.DT_el || 'div')+'/>' )
+								.appendTo( container );
+							attach( inner, button );
+						}
+						else {
+							btnDisplay = '';
+							btnClass = '';
+	
+							switch ( button ) {
+								case 'ellipsis':
+									container.append('<span class="ellipsis">&#x2026;</span>');
+									break;
+	
+								case 'first':
+									btnDisplay = lang.sFirst;
+									btnClass = button + (page > 0 ?
+										'' : ' '+classes.sPageButtonDisabled);
+									break;
+	
+								case 'previous':
+									btnDisplay = lang.sPrevious;
+									btnClass = button + (page > 0 ?
+										'' : ' '+classes.sPageButtonDisabled);
+									break;
+	
+								case 'next':
+									btnDisplay = lang.sNext;
+									btnClass = button + (page < pages-1 ?
+										'' : ' '+classes.sPageButtonDisabled);
+									break;
+	
+								case 'last':
+									btnDisplay = lang.sLast;
+									btnClass = button + (page < pages-1 ?
+										'' : ' '+classes.sPageButtonDisabled);
+									break;
+	
+								default:
+									btnDisplay = button + 1;
+									btnClass = page === button ?
+										classes.sPageButtonActive : '';
+									break;
+							}
+	
+							if ( btnDisplay ) {
+								node = $('<a>', {
+										'class': classes.sPageButton+' '+btnClass,
+										'aria-controls': settings.sTableId,
+										'data-dt-idx': counter,
+										'tabindex': settings.iTabIndex,
+										'id': idx === 0 && typeof button === 'string' ?
+											settings.sTableId +'_'+ button :
+											null
+									} )
+									.html( btnDisplay )
+									.appendTo( container );
+	
+								_fnBindAction(
+									node, {action: button}, clickHandler
+								);
+	
+								counter++;
+							}
+						}
+					}
+				};
+	
+				// IE9 throws an 'unknown error' if document.activeElement is used
+				// inside an iframe or frame. Try / catch the error. Not good for
+				// accessibility, but neither are frames.
+				var activeEl;
+	
+				try {
+					// Because this approach is destroying and recreating the paging
+					// elements, focus is lost on the select button which is bad for
+					// accessibility. So we want to restore focus once the draw has
+					// completed
+					activeEl = $(document.activeElement).data('dt-idx');
+				}
+				catch (e) {}
+	
+				attach( $(host).empty(), buttons );
+	
+				if ( activeEl ) {
+					$(host).find( '[data-dt-idx='+activeEl+']' ).focus();
+				}
+			}
+		}
+	} );
+	
+	
+	
+	// Built in type detection. See model.ext.aTypes for information about
+	// what is required from this methods.
+	$.extend( DataTable.ext.type.detect, [
+		// Plain numbers - first since V8 detects some plain numbers as dates
+		// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
+		function ( d, settings )
+		{
+			var decimal = settings.oLanguage.sDecimal;
+			return _isNumber( d, decimal ) ? 'num'+decimal : null;
+		},
+	
+		// Dates (only those recognised by the browser's Date.parse)
+		function ( d, settings )
+		{
+			// V8 will remove any unknown characters at the start and end of the
+			// expression, leading to false matches such as `$245.12` or `10%` being
+			// a valid date. See forum thread 18941 for detail.
+			if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
+				return null;
+			}
+			var parsed = Date.parse(d);
+			return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
+		},
+	
+		// Formatted numbers
+		function ( d, settings )
+		{
+			var decimal = settings.oLanguage.sDecimal;
+			return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
+		},
+	
+		// HTML numeric
+		function ( d, settings )
+		{
+			var decimal = settings.oLanguage.sDecimal;
+			return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
+		},
+	
+		// HTML numeric, formatted
+		function ( d, settings )
+		{
+			var decimal = settings.oLanguage.sDecimal;
+			return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
+		},
+	
+		// HTML (this is strict checking - there must be html)
+		function ( d, settings )
+		{
+			return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
+				'html' : null;
+		}
+	] );
+	
+	
+	
+	// Filter formatting functions. See model.ext.ofnSearch for information about
+	// what is required from these methods.
+	// 
+	// Note that additional search methods are added for the html numbers and
+	// html formatted numbers by `_addNumericSort()` when we know what the decimal
+	// place is
+	
+	
+	$.extend( DataTable.ext.type.search, {
+		html: function ( data ) {
+			return _empty(data) ?
+				data :
+				typeof data === 'string' ?
+					data
+						.replace( _re_new_lines, " " )
+						.replace( _re_html, "" ) :
+					'';
+		},
+	
+		string: function ( data ) {
+			return _empty(data) ?
+				data :
+				typeof data === 'string' ?
+					data.replace( _re_new_lines, " " ) :
+					data;
+		}
+	} );
+	
+	
+	
+	var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
+		if ( d !== 0 && (!d || d === '-') ) {
+			return -Infinity;
+		}
+	
+		// If a decimal place other than `.` is used, it needs to be given to the
+		// function so we can detect it and replace with a `.` which is the only
+		// decimal place Javascript recognises - it is not locale aware.
+		if ( decimalPlace ) {
+			d = _numToDecimal( d, decimalPlace );
+		}
+	
+		if ( d.replace ) {
+			if ( re1 ) {
+				d = d.replace( re1, '' );
+			}
+	
+			if ( re2 ) {
+				d = d.replace( re2, '' );
+			}
+		}
+	
+		return d * 1;
+	};
+	
+	
+	// Add the numeric 'deformatting' functions for sorting and search. This is done
+	// in a function to provide an easy ability for the language options to add
+	// additional methods if a non-period decimal place is used.
+	function _addNumericSort ( decimalPlace ) {
+		$.each(
+			{
+				// Plain numbers
+				"num": function ( d ) {
+					return __numericReplace( d, decimalPlace );
+				},
+	
+				// Formatted numbers
+				"num-fmt": function ( d ) {
+					return __numericReplace( d, decimalPlace, _re_formatted_numeric );
+				},
+	
+				// HTML numeric
+				"html-num": function ( d ) {
+					return __numericReplace( d, decimalPlace, _re_html );
+				},
+	
+				// HTML numeric, formatted
+				"html-num-fmt": function ( d ) {
+					return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
+				}
+			},
+			function ( key, fn ) {
+				// Add the ordering method
+				_ext.type.order[ key+decimalPlace+'-pre' ] = fn;
+	
+				// For HTML types add a search formatter that will strip the HTML
+				if ( key.match(/^html\-/) ) {
+					_ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
+				}
+			}
+		);
+	}
+	
+	
+	// Default sort methods
+	$.extend( _ext.type.order, {
+		// Dates
+		"date-pre": function ( d ) {
+			return Date.parse( d ) || 0;
+		},
+	
+		// html
+		"html-pre": function ( a ) {
+			return _empty(a) ?
+				'' :
+				a.replace ?
+					a.replace( /<.*?>/g, "" ).toLowerCase() :
+					a+'';
+		},
+	
+		// string
+		"string-pre": function ( a ) {
+			// This is a little complex, but faster than always calling toString,
+			// http://jsperf.com/tostring-v-check
+			return _empty(a) ?
+				'' :
+				typeof a === 'string' ?
+					a.toLowerCase() :
+					! a.toString ?
+						'' :
+						a.toString();
+		},
+	
+		// string-asc and -desc are retained only for compatibility with the old
+		// sort methods
+		"string-asc": function ( x, y ) {
+			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+		},
+	
+		"string-desc": function ( x, y ) {
+			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+		}
+	} );
+	
+	
+	// Numeric sorting types - order doesn't matter here
+	_addNumericSort( '' );
+	
+	
+	$.extend( true, DataTable.ext.renderer, {
+		header: {
+			_: function ( settings, cell, column, classes ) {
+				// No additional mark-up required
+				// Attach a sort listener to update on sort - note that using the
+				// `DT` namespace will allow the event to be removed automatically
+				// on destroy, while the `dt` namespaced event is the one we are
+				// listening for
+				$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
+					if ( settings !== ctx ) { // need to check this this is the host
+						return;               // table, not a nested one
+					}
+	
+					var colIdx = column.idx;
+	
+					cell
+						.removeClass(
+							column.sSortingClass +' '+
+							classes.sSortAsc +' '+
+							classes.sSortDesc
+						)
+						.addClass( columns[ colIdx ] == 'asc' ?
+							classes.sSortAsc : columns[ colIdx ] == 'desc' ?
+								classes.sSortDesc :
+								column.sSortingClass
+						);
+				} );
+			},
+	
+			jqueryui: function ( settings, cell, column, classes ) {
+				$('<div/>')
+					.addClass( classes.sSortJUIWrapper )
+					.append( cell.contents() )
+					.append( $('<span/>')
+						.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
+					)
+					.appendTo( cell );
+	
+				// Attach a sort listener to update on sort
+				$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
+					if ( settings !== ctx ) {
+						return;
+					}
+	
+					var colIdx = column.idx;
+	
+					cell
+						.removeClass( classes.sSortAsc +" "+classes.sSortDesc )
+						.addClass( columns[ colIdx ] == 'asc' ?
+							classes.sSortAsc : columns[ colIdx ] == 'desc' ?
+								classes.sSortDesc :
+								column.sSortingClass
+						);
+	
+					cell
+						.find( 'span.'+classes.sSortIcon )
+						.removeClass(
+							classes.sSortJUIAsc +" "+
+							classes.sSortJUIDesc +" "+
+							classes.sSortJUI +" "+
+							classes.sSortJUIAscAllowed +" "+
+							classes.sSortJUIDescAllowed
+						)
+						.addClass( columns[ colIdx ] == 'asc' ?
+							classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
+								classes.sSortJUIDesc :
+								column.sSortingClassJUI
+						);
+				} );
+			}
+		}
+	} );
+	
+	/*
+	 * Public helper functions. These aren't used internally by DataTables, or
+	 * called by any of the options passed into DataTables, but they can be used
+	 * externally by developers working with DataTables. They are helper functions
+	 * to make working with DataTables a little bit easier.
+	 */
+	
+	/**
+	 * Helpers for `columns.render`.
+	 *
+	 * The options defined here can be used with the `columns.render` initialisation
+	 * option to provide a display renderer. The following functions are defined:
+	 *
+	 * * `number` - Will format numeric data (defined by `columns.data`) for
+	 *   display, retaining the original unformatted data for sorting and filtering.
+	 *   It takes 4 parameters:
+	 *   * `string` - Thousands grouping separator
+	 *   * `string` - Decimal point indicator
+	 *   * `integer` - Number of decimal points to show
+	 *   * `string` (optional) - Prefix.
+	 *
+	 * @example
+	 *   // Column definition using the number renderer
+	 *   {
+	 *     data: "salary",
+	 *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
+	 *   }
+	 *
+	 * @namespace
+	 */
+	DataTable.render = {
+		number: function ( thousands, decimal, precision, prefix ) {
+			return {
+				display: function ( d ) {
+					if ( typeof d !== 'number' && typeof d !== 'string' ) {
+						return d;
+					}
+	
+					var negative = d < 0 ? '-' : '';
+					d = Math.abs( parseFloat( d ) );
+	
+					var intPart = parseInt( d, 10 );
+					var floatPart = precision ?
+						decimal+(d - intPart).toFixed( precision ).substring( 2 ):
+						'';
+	
+					return negative + (prefix||'') +
+						intPart.toString().replace(
+							/\B(?=(\d{3})+(?!\d))/g, thousands
+						) +
+						floatPart;
+				}
+			};
+		}
+	};
+	
+	
+	/*
+	 * This is really a good bit rubbish this method of exposing the internal methods
+	 * publicly... - To be fixed in 2.0 using methods on the prototype
+	 */
+	
+	
+	/**
+	 * Create a wrapper function for exporting an internal functions to an external API.
+	 *  @param {string} fn API function name
+	 *  @returns {function} wrapped function
+	 *  @memberof DataTable#internal
+	 */
+	function _fnExternApiFunc (fn)
+	{
+		return function() {
+			var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
+				Array.prototype.slice.call(arguments)
+			);
+			return DataTable.ext.internal[fn].apply( this, args );
+		};
+	}
+	
+	
+	/**
+	 * Reference to internal functions for use by plug-in developers. Note that
+	 * these methods are references to internal functions and are considered to be
+	 * private. If you use these methods, be aware that they are liable to change
+	 * between versions.
+	 *  @namespace
+	 */
+	$.extend( DataTable.ext.internal, {
+		_fnExternApiFunc: _fnExternApiFunc,
+		_fnBuildAjax: _fnBuildAjax,
+		_fnAjaxUpdate: _fnAjaxUpdate,
+		_fnAjaxParameters: _fnAjaxParameters,
+		_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
+		_fnAjaxDataSrc: _fnAjaxDataSrc,
+		_fnAddColumn: _fnAddColumn,
+		_fnColumnOptions: _fnColumnOptions,
+		_fnAdjustColumnSizing: _fnAdjustColumnSizing,
+		_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
+		_fnColumnIndexToVisible: _fnColumnIndexToVisible,
+		_fnVisbleColumns: _fnVisbleColumns,
+		_fnGetColumns: _fnGetColumns,
+		_fnColumnTypes: _fnColumnTypes,
+		_fnApplyColumnDefs: _fnApplyColumnDefs,
+		_fnHungarianMap: _fnHungarianMap,
+		_fnCamelToHungarian: _fnCamelToHungarian,
+		_fnLanguageCompat: _fnLanguageCompat,
+		_fnBrowserDetect: _fnBrowserDetect,
+		_fnAddData: _fnAddData,
+		_fnAddTr: _fnAddTr,
+		_fnNodeToDataIndex: _fnNodeToDataIndex,
+		_fnNodeToColumnIndex: _fnNodeToColumnIndex,
+		_fnGetCellData: _fnGetCellData,
+		_fnSetCellData: _fnSetCellData,
+		_fnSplitObjNotation: _fnSplitObjNotation,
+		_fnGetObjectDataFn: _fnGetObjectDataFn,
+		_fnSetObjectDataFn: _fnSetObjectDataFn,
+		_fnGetDataMaster: _fnGetDataMaster,
+		_fnClearTable: _fnClearTable,
+		_fnDeleteIndex: _fnDeleteIndex,
+		_fnInvalidate: _fnInvalidate,
+		_fnGetRowElements: _fnGetRowElements,
+		_fnCreateTr: _fnCreateTr,
+		_fnBuildHead: _fnBuildHead,
+		_fnDrawHead: _fnDrawHead,
+		_fnDraw: _fnDraw,
+		_fnReDraw: _fnReDraw,
+		_fnAddOptionsHtml: _fnAddOptionsHtml,
+		_fnDetectHeader: _fnDetectHeader,
+		_fnGetUniqueThs: _fnGetUniqueThs,
+		_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
+		_fnFilterComplete: _fnFilterComplete,
+		_fnFilterCustom: _fnFilterCustom,
+		_fnFilterColumn: _fnFilterColumn,
+		_fnFilter: _fnFilter,
+		_fnFilterCreateSearch: _fnFilterCreateSearch,
+		_fnEscapeRegex: _fnEscapeRegex,
+		_fnFilterData: _fnFilterData,
+		_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
+		_fnUpdateInfo: _fnUpdateInfo,
+		_fnInfoMacros: _fnInfoMacros,
+		_fnInitialise: _fnInitialise,
+		_fnInitComplete: _fnInitComplete,
+		_fnLengthChange: _fnLengthChange,
+		_fnFeatureHtmlLength: _fnFeatureHtmlLength,
+		_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
+		_fnPageChange: _fnPageChange,
+		_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
+		_fnProcessingDisplay: _fnProcessingDisplay,
+		_fnFeatureHtmlTable: _fnFeatureHtmlTable,
+		_fnScrollDraw: _fnScrollDraw,
+		_fnApplyToChildren: _fnApplyToChildren,
+		_fnCalculateColumnWidths: _fnCalculateColumnWidths,
+		_fnThrottle: _fnThrottle,
+		_fnConvertToWidth: _fnConvertToWidth,
+		_fnScrollingWidthAdjust: _fnScrollingWidthAdjust,
+		_fnGetWidestNode: _fnGetWidestNode,
+		_fnGetMaxLenString: _fnGetMaxLenString,
+		_fnStringToCss: _fnStringToCss,
+		_fnScrollBarWidth: _fnScrollBarWidth,
+		_fnSortFlatten: _fnSortFlatten,
+		_fnSort: _fnSort,
+		_fnSortAria: _fnSortAria,
+		_fnSortListener: _fnSortListener,
+		_fnSortAttachListener: _fnSortAttachListener,
+		_fnSortingClasses: _fnSortingClasses,
+		_fnSortData: _fnSortData,
+		_fnSaveState: _fnSaveState,
+		_fnLoadState: _fnLoadState,
+		_fnSettingsFromNode: _fnSettingsFromNode,
+		_fnLog: _fnLog,
+		_fnMap: _fnMap,
+		_fnBindAction: _fnBindAction,
+		_fnCallbackReg: _fnCallbackReg,
+		_fnCallbackFire: _fnCallbackFire,
+		_fnLengthOverflow: _fnLengthOverflow,
+		_fnRenderer: _fnRenderer,
+		_fnDataSource: _fnDataSource,
+		_fnRowAttributes: _fnRowAttributes,
+		_fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
+		                                // in 1.10, so this dead-end function is
+		                                // added to prevent errors
+	} );
+	
+
+	// jQuery access
+	$.fn.dataTable = DataTable;
+
+	// Legacy aliases
+	$.fn.dataTableSettings = DataTable.settings;
+	$.fn.dataTableExt = DataTable.ext;
+
+	// With a capital `D` we return a DataTables API instance rather than a
+	// jQuery object
+	$.fn.DataTable = function ( opts ) {
+		return $(this).dataTable( opts ).api();
+	};
+
+	// All properties that are available to $.fn.dataTable should also be
+	// available on $.fn.DataTable
+	$.each( DataTable, function ( prop, val ) {
+		$.fn.DataTable[ prop ] = val;
+	} );
+
+
+	// Information about events fired by DataTables - for documentation.
+	/**
+	 * Draw event, fired whenever the table is redrawn on the page, at the same
+	 * point as fnDrawCallback. This may be useful for binding events or
+	 * performing calculations when the table is altered at all.
+	 *  @name DataTable#draw.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+	 */
+
+	/**
+	 * Search event, fired when the searching applied to the table (using the
+	 * built-in global search, or column filters) is altered.
+	 *  @name DataTable#search.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+	 */
+
+	/**
+	 * Page change event, fired when the paging of the table is altered.
+	 *  @name DataTable#page.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+	 */
+
+	/**
+	 * Order event, fired when the ordering applied to the table is altered.
+	 *  @name DataTable#order.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+	 */
+
+	/**
+	 * DataTables initialisation complete event, fired when the table is fully
+	 * drawn, including Ajax data loaded, if Ajax data is required.
+	 *  @name DataTable#init.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} oSettings DataTables settings object
+	 *  @param {object} json The JSON object request from the server - only
+	 *    present if client-side Ajax sourced data is used</li></ol>
+	 */
+
+	/**
+	 * State save event, fired when the table has changed state a new state save
+	 * is required. This event allows modification of the state saving object
+	 * prior to actually doing the save, including addition or other state
+	 * properties (for plug-ins) or modification of a DataTables core property.
+	 *  @name DataTable#stateSaveParams.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} oSettings DataTables settings object
+	 *  @param {object} json The state information to be saved
+	 */
+
+	/**
+	 * State load event, fired when the table is loading state from the stored
+	 * data, but prior to the settings object being modified by the saved state
+	 * - allowing modification of the saved state is required or loading of
+	 * state for a plug-in.
+	 *  @name DataTable#stateLoadParams.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} oSettings DataTables settings object
+	 *  @param {object} json The saved state information
+	 */
+
+	/**
+	 * State loaded event, fired when state has been loaded from stored data and
+	 * the settings object has been modified by the loaded data.
+	 *  @name DataTable#stateLoaded.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} oSettings DataTables settings object
+	 *  @param {object} json The saved state information
+	 */
+
+	/**
+	 * Processing event, fired when DataTables is doing some kind of processing
+	 * (be it, order, searcg or anything else). It can be used to indicate to
+	 * the end user that there is something happening, or that something has
+	 * finished.
+	 *  @name DataTable#processing.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} oSettings DataTables settings object
+	 *  @param {boolean} bShow Flag for if DataTables is doing processing or not
+	 */
+
+	/**
+	 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
+	 * request to made to the server for new data. This event is called before
+	 * DataTables processed the returned data, so it can also be used to pre-
+	 * process the data returned from the server, if needed.
+	 *
+	 * Note that this trigger is called in `fnServerData`, if you override
+	 * `fnServerData` and which to use this event, you need to trigger it in you
+	 * success function.
+	 *  @name DataTable#xhr.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+	 *  @param {object} json JSON returned from the server
+	 *
+	 *  @example
+	 *     // Use a custom property returned from the server in another DOM element
+	 *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
+	 *       $('#status').html( json.status );
+	 *     } );
+	 *
+	 *  @example
+	 *     // Pre-process the data returned from the server
+	 *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
+	 *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
+	 *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
+	 *       }
+	 *       // Note no return - manipulate the data directly in the JSON object.
+	 *     } );
+	 */
+
+	/**
+	 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
+	 * or passing the bDestroy:true parameter in the initialisation object. This
+	 * can be used to remove bound events, added DOM nodes, etc.
+	 *  @name DataTable#destroy.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+	 */
+
+	/**
+	 * Page length change event, fired when number of records to show on each
+	 * page (the length) is changed.
+	 *  @name DataTable#length.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+	 *  @param {integer} len New length
+	 */
+
+	/**
+	 * Column sizing has changed.
+	 *  @name DataTable#column-sizing.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+	 */
+
+	/**
+	 * Column visibility has changed.
+	 *  @name DataTable#column-visibility.dt
+	 *  @event
+	 *  @param {event} e jQuery event object
+	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+	 *  @param {int} column Column index
+	 *  @param {bool} vis `false` if column now hidden, or `true` if visible
+	 */
+
+	return $.fn.dataTable;
+}));
+
+}(window, document));
+
diff --git a/htdocs/Libs/DataTables-1.10.3/media/js/jquery.dataTables.min.js b/htdocs/Libs/DataTables-1.10.3/media/js/jquery.dataTables.min.js
new file mode 100644
index 0000000..85dd817
--- /dev/null
+++ b/htdocs/Libs/DataTables-1.10.3/media/js/jquery.dataTables.min.js
@@ -0,0 +1,160 @@
+/*! DataTables 1.10.7
+ * ©2008-2015 SpryMedia Ltd - datatables.net/license
+ */
+(function(Ea,Q,k){var P=function(h){function W(a){var b,c,e={};h.each(a,function(d){if((b=d.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(b[1]+" "))c=d.replace(b[0],b[2].toLowerCase()),e[c]=d,"o"===b[1]&&W(a[d])});a._hungarianMap=e}function H(a,b,c){a._hungarianMap||W(a);var e;h.each(b,function(d){e=a._hungarianMap[d];if(e!==k&&(c||b[e]===k))"o"===e.charAt(0)?(b[e]||(b[e]={}),h.extend(!0,b[e],b[d]),H(a[e],b[e],c)):b[e]=b[d]})}function P(a){var b=m.defaults.oLanguage,c=a.sZeroRecords;
+!a.sEmptyTable&&(c&&"No data available in table"===b.sEmptyTable)&&E(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&(c&&"Loading..."===b.sLoadingRecords)&&E(a,a,"sZeroRecords","sLoadingRecords");a.sInfoThousands&&(a.sThousands=a.sInfoThousands);(a=a.sDecimal)&&db(a)}function eb(a){A(a,"ordering","bSort");A(a,"orderMulti","bSortMulti");A(a,"orderClasses","bSortClasses");A(a,"orderCellsTop","bSortCellsTop");A(a,"order","aaSorting");A(a,"orderFixed","aaSortingFixed");A(a,"paging","bPaginate");
+A(a,"pagingType","sPaginationType");A(a,"pageLength","iDisplayLength");A(a,"searching","bFilter");if(a=a.aoSearchCols)for(var b=0,c=a.length;b<c;b++)a[b]&&H(m.models.oSearch,a[b])}function fb(a){A(a,"orderable","bSortable");A(a,"orderData","aDataSort");A(a,"orderSequence","asSorting");A(a,"orderDataType","sortDataType");var b=a.aDataSort;b&&!h.isArray(b)&&(a.aDataSort=[b])}function gb(a){var a=a.oBrowser,b=h("<div/>").css({position:"absolute",top:0,left:0,height:1,width:1,overflow:"hidden"}).append(h("<div/>").css({position:"absolute",
+top:1,left:1,width:100,overflow:"scroll"}).append(h('<div class="test"/>').css({width:"100%",height:10}))).appendTo("body"),c=b.find(".test");a.bScrollOversize=100===c[0].offsetWidth;a.bScrollbarLeft=1!==Math.round(c.offset().left);b.remove()}function hb(a,b,c,e,d,f){var g,j=!1;c!==k&&(g=c,j=!0);for(;e!==d;)a.hasOwnProperty(e)&&(g=j?b(g,a[e],e,a):a[e],j=!0,e+=f);return g}function Fa(a,b){var c=m.defaults.column,e=a.aoColumns.length,c=h.extend({},m.models.oColumn,c,{nTh:b?b:Q.createElement("th"),sTitle:c.sTitle?
+c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[e],mData:c.mData?c.mData:e,idx:e});a.aoColumns.push(c);c=a.aoPreSearchCols;c[e]=h.extend({},m.models.oSearch,c[e]);ka(a,e,h(b).data())}function ka(a,b,c){var b=a.aoColumns[b],e=a.oClasses,d=h(b.nTh);if(!b.sWidthOrig){b.sWidthOrig=d.attr("width")||null;var f=(d.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);f&&(b.sWidthOrig=f[1])}c!==k&&null!==c&&(fb(c),H(m.defaults.column,c),c.mDataProp!==k&&!c.mData&&(c.mData=c.mDataProp),c.sType&&
+(b._sManualType=c.sType),c.className&&!c.sClass&&(c.sClass=c.className),h.extend(b,c),E(b,c,"sWidth","sWidthOrig"),c.iDataSort!==k&&(b.aDataSort=[c.iDataSort]),E(b,c,"aDataSort"));var g=b.mData,j=R(g),i=b.mRender?R(b.mRender):null,c=function(a){return"string"===typeof a&&-1!==a.indexOf("@")};b._bAttrSrc=h.isPlainObject(g)&&(c(g.sort)||c(g.type)||c(g.filter));b.fnGetData=function(a,b,c){var e=j(a,b,k,c);return i&&b?i(e,b,a,c):e};b.fnSetData=function(a,b,c){return S(g)(a,b,c)};"number"!==typeof g&&
+(a._rowReadObject=!0);a.oFeatures.bSort||(b.bSortable=!1,d.addClass(e.sSortableNone));a=-1!==h.inArray("asc",b.asSorting);c=-1!==h.inArray("desc",b.asSorting);!b.bSortable||!a&&!c?(b.sSortingClass=e.sSortableNone,b.sSortingClassJUI=""):a&&!c?(b.sSortingClass=e.sSortableAsc,b.sSortingClassJUI=e.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=e.sSortableDesc,b.sSortingClassJUI=e.sSortJUIDescAllowed):(b.sSortingClass=e.sSortable,b.sSortingClassJUI=e.sSortJUI)}function X(a){if(!1!==a.oFeatures.bAutoWidth){var b=
+a.aoColumns;Ga(a);for(var c=0,e=b.length;c<e;c++)b[c].nTh.style.width=b[c].sWidth}b=a.oScroll;(""!==b.sY||""!==b.sX)&&Y(a);w(a,null,"column-sizing",[a])}function la(a,b){var c=Z(a,"bVisible");return"number"===typeof c[b]?c[b]:null}function $(a,b){var c=Z(a,"bVisible"),c=h.inArray(b,c);return-1!==c?c:null}function aa(a){return Z(a,"bVisible").length}function Z(a,b){var c=[];h.map(a.aoColumns,function(a,d){a[b]&&c.push(d)});return c}function Ha(a){var b=a.aoColumns,c=a.aoData,e=m.ext.type.detect,d,
+f,g,j,i,h,l,q,n;d=0;for(f=b.length;d<f;d++)if(l=b[d],n=[],!l.sType&&l._sManualType)l.sType=l._sManualType;else if(!l.sType){g=0;for(j=e.length;g<j;g++){i=0;for(h=c.length;i<h;i++){n[i]===k&&(n[i]=x(a,i,d,"type"));q=e[g](n[i],a);if(!q&&g!==e.length-1)break;if("html"===q)break}if(q){l.sType=q;break}}l.sType||(l.sType="string")}}function ib(a,b,c,e){var d,f,g,j,i,o,l=a.aoColumns;if(b)for(d=b.length-1;0<=d;d--){o=b[d];var q=o.targets!==k?o.targets:o.aTargets;h.isArray(q)||(q=[q]);f=0;for(g=q.length;f<
+g;f++)if("number"===typeof q[f]&&0<=q[f]){for(;l.length<=q[f];)Fa(a);e(q[f],o)}else if("number"===typeof q[f]&&0>q[f])e(l.length+q[f],o);else if("string"===typeof q[f]){j=0;for(i=l.length;j<i;j++)("_all"==q[f]||h(l[j].nTh).hasClass(q[f]))&&e(j,o)}}if(c){d=0;for(a=c.length;d<a;d++)e(d,c[d])}}function K(a,b,c,e){var d=a.aoData.length,f=h.extend(!0,{},m.models.oRow,{src:c?"dom":"data"});f._aData=b;a.aoData.push(f);for(var b=a.aoColumns,f=0,g=b.length;f<g;f++)c&&Ia(a,d,f,x(a,d,f)),b[f].sType=null;a.aiDisplayMaster.push(d);
+(c||!a.oFeatures.bDeferRender)&&Ja(a,d,c,e);return d}function ma(a,b){var c;b instanceof h||(b=h(b));return b.map(function(b,d){c=na(a,d);return K(a,c.data,d,c.cells)})}function x(a,b,c,e){var d=a.iDraw,f=a.aoColumns[c],g=a.aoData[b]._aData,j=f.sDefaultContent,c=f.fnGetData(g,e,{settings:a,row:b,col:c});if(c===k)return a.iDrawError!=d&&null===j&&(I(a,0,"Requested unknown parameter "+("function"==typeof f.mData?"{function}":"'"+f.mData+"'")+" for row "+b,4),a.iDrawError=d),j;if((c===g||null===c)&&
+null!==j)c=j;else if("function"===typeof c)return c.call(g);return null===c&&"display"==e?"":c}function Ia(a,b,c,e){a.aoColumns[c].fnSetData(a.aoData[b]._aData,e,{settings:a,row:b,col:c})}function Ka(a){return h.map(a.match(/(\\.|[^\.])+/g),function(a){return a.replace(/\\./g,".")})}function R(a){if(h.isPlainObject(a)){var b={};h.each(a,function(a,c){c&&(b[a]=R(c))});return function(a,c,f,g){var j=b[c]||b._;return j!==k?j(a,c,f,g):a}}if(null===a)return function(a){return a};if("function"===typeof a)return function(b,
+c,f,g){return a(b,c,f,g)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var c=function(a,b,f){var g,j;if(""!==f){j=Ka(f);for(var i=0,h=j.length;i<h;i++){f=j[i].match(ba);g=j[i].match(T);if(f){j[i]=j[i].replace(ba,"");""!==j[i]&&(a=a[j[i]]);g=[];j.splice(0,i+1);j=j.join(".");i=0;for(h=a.length;i<h;i++)g.push(c(a[i],b,j));a=f[0].substring(1,f[0].length-1);a=""===a?g:g.join(a);break}else if(g){j[i]=j[i].replace(T,"");a=a[j[i]]();continue}if(null===a||a[j[i]]===
+k)return k;a=a[j[i]]}}return a};return function(b,d){return c(b,d,a)}}return function(b){return b[a]}}function S(a){if(h.isPlainObject(a))return S(a._);if(null===a)return function(){};if("function"===typeof a)return function(b,e,d){a(b,"set",e,d)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var b=function(a,e,d){var d=Ka(d),f;f=d[d.length-1];for(var g,j,i=0,h=d.length-1;i<h;i++){g=d[i].match(ba);j=d[i].match(T);if(g){d[i]=d[i].replace(ba,"");a[d[i]]=[];
+f=d.slice();f.splice(0,i+1);g=f.join(".");j=0;for(h=e.length;j<h;j++)f={},b(f,e[j],g),a[d[i]].push(f);return}j&&(d[i]=d[i].replace(T,""),a=a[d[i]](e));if(null===a[d[i]]||a[d[i]]===k)a[d[i]]={};a=a[d[i]]}if(f.match(T))a[f.replace(T,"")](e);else a[f.replace(ba,"")]=e};return function(c,e){return b(c,e,a)}}return function(b,e){b[a]=e}}function La(a){return D(a.aoData,"_aData")}function oa(a){a.aoData.length=0;a.aiDisplayMaster.length=0;a.aiDisplay.length=0}function pa(a,b,c){for(var e=-1,d=0,f=a.length;d<
+f;d++)a[d]==b?e=d:a[d]>b&&a[d]--; -1!=e&&c===k&&a.splice(e,1)}function ca(a,b,c,e){var d=a.aoData[b],f,g=function(c,f){for(;c.childNodes.length;)c.removeChild(c.firstChild);c.innerHTML=x(a,b,f,"display")};if("dom"===c||(!c||"auto"===c)&&"dom"===d.src)d._aData=na(a,d,e,e===k?k:d._aData).data;else{var j=d.anCells;if(j)if(e!==k)g(j[e],e);else{c=0;for(f=j.length;c<f;c++)g(j[c],c)}}d._aSortData=null;d._aFilterData=null;g=a.aoColumns;if(e!==k)g[e].sType=null;else{c=0;for(f=g.length;c<f;c++)g[c].sType=null;
+Ma(d)}}function na(a,b,c,e){var d=[],f=b.firstChild,g,j=0,i,o=a.aoColumns,l=a._rowReadObject,e=e||l?{}:[],q=function(a,b){if("string"===typeof a){var c=a.indexOf("@");-1!==c&&(c=a.substring(c+1),S(a)(e,b.getAttribute(c)))}},a=function(a){if(c===k||c===j)g=o[j],i=h.trim(a.innerHTML),g&&g._bAttrSrc?(S(g.mData._)(e,i),q(g.mData.sort,a),q(g.mData.type,a),q(g.mData.filter,a)):l?(g._setter||(g._setter=S(g.mData)),g._setter(e,i)):e[j]=i;j++};if(f)for(;f;){b=f.nodeName.toUpperCase();if("TD"==b||"TH"==b)a(f),
+d.push(f);f=f.nextSibling}else{d=b.anCells;f=0;for(b=d.length;f<b;f++)a(d[f])}return{data:e,cells:d}}function Ja(a,b,c,e){var d=a.aoData[b],f=d._aData,g=[],j,i,h,l,q;if(null===d.nTr){j=c||Q.createElement("tr");d.nTr=j;d.anCells=g;j._DT_RowIndex=b;Ma(d);l=0;for(q=a.aoColumns.length;l<q;l++){h=a.aoColumns[l];i=c?e[l]:Q.createElement(h.sCellType);g.push(i);if(!c||h.mRender||h.mData!==l)i.innerHTML=x(a,b,l,"display");h.sClass&&(i.className+=" "+h.sClass);h.bVisible&&!c?j.appendChild(i):!h.bVisible&&c&&
+i.parentNode.removeChild(i);h.fnCreatedCell&&h.fnCreatedCell.call(a.oInstance,i,x(a,b,l),f,b,l)}w(a,"aoRowCreatedCallback",null,[j,f,b])}d.nTr.setAttribute("role","row")}function Ma(a){var b=a.nTr,c=a._aData;if(b){c.DT_RowId&&(b.id=c.DT_RowId);if(c.DT_RowClass){var e=c.DT_RowClass.split(" ");a.__rowc=a.__rowc?Na(a.__rowc.concat(e)):e;h(b).removeClass(a.__rowc.join(" ")).addClass(c.DT_RowClass)}c.DT_RowAttr&&h(b).attr(c.DT_RowAttr);c.DT_RowData&&h(b).data(c.DT_RowData)}}function jb(a){var b,c,e,d,
+f,g=a.nTHead,j=a.nTFoot,i=0===h("th, td",g).length,o=a.oClasses,l=a.aoColumns;i&&(d=h("<tr/>").appendTo(g));b=0;for(c=l.length;b<c;b++)f=l[b],e=h(f.nTh).addClass(f.sClass),i&&e.appendTo(d),a.oFeatures.bSort&&(e.addClass(f.sSortingClass),!1!==f.bSortable&&(e.attr("tabindex",a.iTabIndex).attr("aria-controls",a.sTableId),Oa(a,f.nTh,b))),f.sTitle!=e.html()&&e.html(f.sTitle),Pa(a,"header")(a,e,f,o);i&&da(a.aoHeader,g);h(g).find(">tr").attr("role","row");h(g).find(">tr>th, >tr>td").addClass(o.sHeaderTH);
+h(j).find(">tr>th, >tr>td").addClass(o.sFooterTH);if(null!==j){a=a.aoFooter[0];b=0;for(c=a.length;b<c;b++)f=l[b],f.nTf=a[b].cell,f.sClass&&h(f.nTf).addClass(f.sClass)}}function ea(a,b,c){var e,d,f,g=[],j=[],i=a.aoColumns.length,o;if(b){c===k&&(c=!1);e=0;for(d=b.length;e<d;e++){g[e]=b[e].slice();g[e].nTr=b[e].nTr;for(f=i-1;0<=f;f--)!a.aoColumns[f].bVisible&&!c&&g[e].splice(f,1);j.push([])}e=0;for(d=g.length;e<d;e++){if(a=g[e].nTr)for(;f=a.firstChild;)a.removeChild(f);f=0;for(b=g[e].length;f<b;f++)if(o=
+i=1,j[e][f]===k){a.appendChild(g[e][f].cell);for(j[e][f]=1;g[e+i]!==k&&g[e][f].cell==g[e+i][f].cell;)j[e+i][f]=1,i++;for(;g[e][f+o]!==k&&g[e][f].cell==g[e][f+o].cell;){for(c=0;c<i;c++)j[e+c][f+o]=1;o++}h(g[e][f].cell).attr("rowspan",i).attr("colspan",o)}}}}function M(a){var b=w(a,"aoPreDrawCallback","preDraw",[a]);if(-1!==h.inArray(!1,b))C(a,!1);else{var b=[],c=0,e=a.asStripeClasses,d=e.length,f=a.oLanguage,g=a.iInitDisplayStart,j="ssp"==B(a),i=a.aiDisplay;a.bDrawing=!0;g!==k&&-1!==g&&(a._iDisplayStart=
+j?g:g>=a.fnRecordsDisplay()?0:g,a.iInitDisplayStart=-1);var g=a._iDisplayStart,o=a.fnDisplayEnd();if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,C(a,!1);else if(j){if(!a.bDestroying&&!kb(a))return}else a.iDraw++;if(0!==i.length){f=j?a.aoData.length:o;for(j=j?0:g;j<f;j++){var l=i[j],q=a.aoData[l];null===q.nTr&&Ja(a,l);l=q.nTr;if(0!==d){var n=e[c%d];q._sRowStripe!=n&&(h(l).removeClass(q._sRowStripe).addClass(n),q._sRowStripe=n)}w(a,"aoRowCallback",null,[l,q._aData,c,j]);b.push(l);c++}}else c=f.sZeroRecords,
+1==a.iDraw&&"ajax"==B(a)?c=f.sLoadingRecords:f.sEmptyTable&&0===a.fnRecordsTotal()&&(c=f.sEmptyTable),b[0]=h("<tr/>",{"class":d?e[0]:""}).append(h("<td />",{valign:"top",colSpan:aa(a),"class":a.oClasses.sRowEmpty}).html(c))[0];w(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],La(a),g,o,i]);w(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],La(a),g,o,i]);e=h(a.nTBody);e.children().detach();e.append(h(b));w(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=
+!1}}function N(a,b){var c=a.oFeatures,e=c.bFilter;c.bSort&&lb(a);e?fa(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;M(a);a._drawHold=!1}function mb(a){var b=a.oClasses,c=h(a.nTable),c=h("<div/>").insertBefore(c),e=a.oFeatures,d=h("<div/>",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=d[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var f=a.sDom.split(""),g,j,i,o,l,q,n=0;n<f.length;n++){g=
+null;j=f[n];if("<"==j){i=h("<div/>")[0];o=f[n+1];if("'"==o||'"'==o){l="";for(q=2;f[n+q]!=o;)l+=f[n+q],q++;"H"==l?l=b.sJUIHeader:"F"==l&&(l=b.sJUIFooter);-1!=l.indexOf(".")?(o=l.split("."),i.id=o[0].substr(1,o[0].length-1),i.className=o[1]):"#"==l.charAt(0)?i.id=l.substr(1,l.length-1):i.className=l;n+=q}d.append(i);d=h(i)}else if(">"==j)d=d.parent();else if("l"==j&&e.bPaginate&&e.bLengthChange)g=nb(a);else if("f"==j&&e.bFilter)g=ob(a);else if("r"==j&&e.bProcessing)g=pb(a);else if("t"==j)g=qb(a);else if("i"==
+j&&e.bInfo)g=rb(a);else if("p"==j&&e.bPaginate)g=sb(a);else if(0!==m.ext.feature.length){i=m.ext.feature;q=0;for(o=i.length;q<o;q++)if(j==i[q].cFeature){g=i[q].fnInit(a);break}}g&&(i=a.aanFeatures,i[j]||(i[j]=[]),i[j].push(g),d.append(g))}c.replaceWith(d)}function da(a,b){var c=h(b).children("tr"),e,d,f,g,j,i,o,l,q,n;a.splice(0,a.length);f=0;for(i=c.length;f<i;f++)a.push([]);f=0;for(i=c.length;f<i;f++){e=c[f];for(d=e.firstChild;d;){if("TD"==d.nodeName.toUpperCase()||"TH"==d.nodeName.toUpperCase()){l=
+1*d.getAttribute("colspan");q=1*d.getAttribute("rowspan");l=!l||0===l||1===l?1:l;q=!q||0===q||1===q?1:q;g=0;for(j=a[f];j[g];)g++;o=g;n=1===l?!0:!1;for(j=0;j<l;j++)for(g=0;g<q;g++)a[f+g][o+j]={cell:d,unique:n},a[f+g].nTr=e}d=d.nextSibling}}}function qa(a,b,c){var e=[];c||(c=a.aoHeader,b&&(c=[],da(c,b)));for(var b=0,d=c.length;b<d;b++)for(var f=0,g=c[b].length;f<g;f++)if(c[b][f].unique&&(!e[f]||!a.bSortCellsTop))e[f]=c[b][f].cell;return e}function ra(a,b,c){w(a,"aoServerParams","serverParams",[b]);
+if(b&&h.isArray(b)){var e={},d=/(.*?)\[\]$/;h.each(b,function(a,b){var c=b.name.match(d);c?(c=c[0],e[c]||(e[c]=[]),e[c].push(b.value)):e[b.name]=b.value});b=e}var f,g=a.ajax,j=a.oInstance,i=function(b){w(a,null,"xhr",[a,b,a.jqXHR]);c(b)};if(h.isPlainObject(g)&&g.data){f=g.data;var o=h.isFunction(f)?f(b,a):f,b=h.isFunction(f)&&o?o:h.extend(!0,b,o);delete g.data}o={data:b,success:function(b){var c=b.error||b.sError;c&&I(a,0,c);a.json=b;i(b)},dataType:"json",cache:!1,type:a.sServerMethod,error:function(b,
+c){var f=w(a,null,"xhr",[a,null,a.jqXHR]);-1===h.inArray(!0,f)&&("parsererror"==c?I(a,0,"Invalid JSON response",1):4===b.readyState&&I(a,0,"Ajax error",7));C(a,!1)}};a.oAjaxData=b;w(a,null,"preXhr",[a,b]);a.fnServerData?a.fnServerData.call(j,a.sAjaxSource,h.map(b,function(a,b){return{name:b,value:a}}),i,a):a.sAjaxSource||"string"===typeof g?a.jqXHR=h.ajax(h.extend(o,{url:g||a.sAjaxSource})):h.isFunction(g)?a.jqXHR=g.call(j,b,i,a):(a.jqXHR=h.ajax(h.extend(o,g)),g.data=f)}function kb(a){return a.bAjaxDataGet?
+(a.iDraw++,C(a,!0),ra(a,tb(a),function(b){ub(a,b)}),!1):!0}function tb(a){var b=a.aoColumns,c=b.length,e=a.oFeatures,d=a.oPreviousSearch,f=a.aoPreSearchCols,g,j=[],i,o,l,q=U(a);g=a._iDisplayStart;i=!1!==e.bPaginate?a._iDisplayLength:-1;var n=function(a,b){j.push({name:a,value:b})};n("sEcho",a.iDraw);n("iColumns",c);n("sColumns",D(b,"sName").join(","));n("iDisplayStart",g);n("iDisplayLength",i);var k={draw:a.iDraw,columns:[],order:[],start:g,length:i,search:{value:d.sSearch,regex:d.bRegex}};for(g=
+0;g<c;g++)o=b[g],l=f[g],i="function"==typeof o.mData?"function":o.mData,k.columns.push({data:i,name:o.sName,searchable:o.bSearchable,orderable:o.bSortable,search:{value:l.sSearch,regex:l.bRegex}}),n("mDataProp_"+g,i),e.bFilter&&(n("sSearch_"+g,l.sSearch),n("bRegex_"+g,l.bRegex),n("bSearchable_"+g,o.bSearchable)),e.bSort&&n("bSortable_"+g,o.bSortable);e.bFilter&&(n("sSearch",d.sSearch),n("bRegex",d.bRegex));e.bSort&&(h.each(q,function(a,b){k.order.push({column:b.col,dir:b.dir});n("iSortCol_"+a,b.col);
+n("sSortDir_"+a,b.dir)}),n("iSortingCols",q.length));b=m.ext.legacy.ajax;return null===b?a.sAjaxSource?j:k:b?j:k}function ub(a,b){var c=sa(a,b),e=b.sEcho!==k?b.sEcho:b.draw,d=b.iTotalRecords!==k?b.iTotalRecords:b.recordsTotal,f=b.iTotalDisplayRecords!==k?b.iTotalDisplayRecords:b.recordsFiltered;if(e){if(1*e<a.iDraw)return;a.iDraw=1*e}oa(a);a._iRecordsTotal=parseInt(d,10);a._iRecordsDisplay=parseInt(f,10);e=0;for(d=c.length;e<d;e++)K(a,c[e]);a.aiDisplay=a.aiDisplayMaster.slice();a.bAjaxDataGet=!1;
+M(a);a._bInitComplete||ta(a,b);a.bAjaxDataGet=!0;C(a,!1)}function sa(a,b){var c=h.isPlainObject(a.ajax)&&a.ajax.dataSrc!==k?a.ajax.dataSrc:a.sAjaxDataProp;return"data"===c?b.aaData||b[c]:""!==c?R(c)(b):b}function ob(a){var b=a.oClasses,c=a.sTableId,e=a.oLanguage,d=a.oPreviousSearch,f=a.aanFeatures,g='<input type="search" class="'+b.sFilterInput+'"/>',j=e.sSearch,j=j.match(/_INPUT_/)?j.replace("_INPUT_",g):j+g,b=h("<div/>",{id:!f.f?c+"_filter":null,"class":b.sFilter}).append(h("<label/>").append(j)),
+f=function(){var b=!this.value?"":this.value;b!=d.sSearch&&(fa(a,{sSearch:b,bRegex:d.bRegex,bSmart:d.bSmart,bCaseInsensitive:d.bCaseInsensitive}),a._iDisplayStart=0,M(a))},g=null!==a.searchDelay?a.searchDelay:"ssp"===B(a)?400:0,i=h("input",b).val(d.sSearch).attr("placeholder",e.sSearchPlaceholder).bind("keyup.DT search.DT input.DT paste.DT cut.DT",g?ua(f,g):f).bind("keypress.DT",function(a){if(13==a.keyCode)return!1}).attr("aria-controls",c);h(a.nTable).on("search.dt.DT",function(b,c){if(a===c)try{i[0]!==
+Q.activeElement&&i.val(d.sSearch)}catch(f){}});return b[0]}function fa(a,b,c){var e=a.oPreviousSearch,d=a.aoPreSearchCols,f=function(a){e.sSearch=a.sSearch;e.bRegex=a.bRegex;e.bSmart=a.bSmart;e.bCaseInsensitive=a.bCaseInsensitive};Ha(a);if("ssp"!=B(a)){vb(a,b.sSearch,c,b.bEscapeRegex!==k?!b.bEscapeRegex:b.bRegex,b.bSmart,b.bCaseInsensitive);f(b);for(b=0;b<d.length;b++)wb(a,d[b].sSearch,b,d[b].bEscapeRegex!==k?!d[b].bEscapeRegex:d[b].bRegex,d[b].bSmart,d[b].bCaseInsensitive);xb(a)}else f(b);a.bFiltered=
+!0;w(a,null,"search",[a])}function xb(a){for(var b=m.ext.search,c=a.aiDisplay,e,d,f=0,g=b.length;f<g;f++){for(var j=[],i=0,h=c.length;i<h;i++)d=c[i],e=a.aoData[d],b[f](a,e._aFilterData,d,e._aData,i)&&j.push(d);c.length=0;c.push.apply(c,j)}}function wb(a,b,c,e,d,f){if(""!==b)for(var g=a.aiDisplay,e=Qa(b,e,d,f),d=g.length-1;0<=d;d--)b=a.aoData[g[d]]._aFilterData[c],e.test(b)||g.splice(d,1)}function vb(a,b,c,e,d,f){var e=Qa(b,e,d,f),d=a.oPreviousSearch.sSearch,f=a.aiDisplayMaster,g;0!==m.ext.search.length&&
+(c=!0);g=yb(a);if(0>=b.length)a.aiDisplay=f.slice();else{if(g||c||d.length>b.length||0!==b.indexOf(d)||a.bSorted)a.aiDisplay=f.slice();b=a.aiDisplay;for(c=b.length-1;0<=c;c--)e.test(a.aoData[b[c]]._sFilterRow)||b.splice(c,1)}}function Qa(a,b,c,e){a=b?a:va(a);c&&(a="^(?=.*?"+h.map(a.match(/"[^"]+"|[^ ]+/g)||[""],function(a){if('"'===a.charAt(0))var b=a.match(/^"(.*)"$/),a=b?b[1]:a;return a.replace('"',"")}).join(")(?=.*?")+").*$");return RegExp(a,e?"i":"")}function va(a){return a.replace(Yb,"\\$1")}
+function yb(a){var b=a.aoColumns,c,e,d,f,g,j,i,h,l=m.ext.type.search;c=!1;e=0;for(f=a.aoData.length;e<f;e++)if(h=a.aoData[e],!h._aFilterData){j=[];d=0;for(g=b.length;d<g;d++)c=b[d],c.bSearchable?(i=x(a,e,d,"filter"),l[c.sType]&&(i=l[c.sType](i)),null===i&&(i=""),"string"!==typeof i&&i.toString&&(i=i.toString())):i="",i.indexOf&&-1!==i.indexOf("&")&&(wa.innerHTML=i,i=Zb?wa.textContent:wa.innerText),i.replace&&(i=i.replace(/[\r\n]/g,"")),j.push(i);h._aFilterData=j;h._sFilterRow=j.join("  ");c=!0}return c}
+function zb(a){return{search:a.sSearch,smart:a.bSmart,regex:a.bRegex,caseInsensitive:a.bCaseInsensitive}}function Ab(a){return{sSearch:a.search,bSmart:a.smart,bRegex:a.regex,bCaseInsensitive:a.caseInsensitive}}function rb(a){var b=a.sTableId,c=a.aanFeatures.i,e=h("<div/>",{"class":a.oClasses.sInfo,id:!c?b+"_info":null});c||(a.aoDrawCallback.push({fn:Bb,sName:"information"}),e.attr("role","status").attr("aria-live","polite"),h(a.nTable).attr("aria-describedby",b+"_info"));return e[0]}function Bb(a){var b=
+a.aanFeatures.i;if(0!==b.length){var c=a.oLanguage,e=a._iDisplayStart+1,d=a.fnDisplayEnd(),f=a.fnRecordsTotal(),g=a.fnRecordsDisplay(),j=g?c.sInfo:c.sInfoEmpty;g!==f&&(j+=" "+c.sInfoFiltered);j+=c.sInfoPostFix;j=Cb(a,j);c=c.fnInfoCallback;null!==c&&(j=c.call(a.oInstance,a,e,d,f,g,j));h(b).html(j)}}function Cb(a,b){var c=a.fnFormatNumber,e=a._iDisplayStart+1,d=a._iDisplayLength,f=a.fnRecordsDisplay(),g=-1===d;return b.replace(/_START_/g,c.call(a,e)).replace(/_END_/g,c.call(a,a.fnDisplayEnd())).replace(/_MAX_/g,
+c.call(a,a.fnRecordsTotal())).replace(/_TOTAL_/g,c.call(a,f)).replace(/_PAGE_/g,c.call(a,g?1:Math.ceil(e/d))).replace(/_PAGES_/g,c.call(a,g?1:Math.ceil(f/d)))}function ga(a){var b,c,e=a.iInitDisplayStart,d=a.aoColumns,f;c=a.oFeatures;if(a.bInitialised){mb(a);jb(a);ea(a,a.aoHeader);ea(a,a.aoFooter);C(a,!0);c.bAutoWidth&&Ga(a);b=0;for(c=d.length;b<c;b++)f=d[b],f.sWidth&&(f.nTh.style.width=s(f.sWidth));N(a);d=B(a);"ssp"!=d&&("ajax"==d?ra(a,[],function(c){var f=sa(a,c);for(b=0;b<f.length;b++)K(a,f[b]);
+a.iInitDisplayStart=e;N(a);C(a,!1);ta(a,c)},a):(C(a,!1),ta(a)))}else setTimeout(function(){ga(a)},200)}function ta(a,b){a._bInitComplete=!0;b&&X(a);w(a,"aoInitComplete","init",[a,b])}function Ra(a,b){var c=parseInt(b,10);a._iDisplayLength=c;Sa(a);w(a,null,"length",[a,c])}function nb(a){for(var b=a.oClasses,c=a.sTableId,e=a.aLengthMenu,d=h.isArray(e[0]),f=d?e[0]:e,e=d?e[1]:e,d=h("<select/>",{name:c+"_length","aria-controls":c,"class":b.sLengthSelect}),g=0,j=f.length;g<j;g++)d[0][g]=new Option(e[g],
+f[g]);var i=h("<div><label/></div>").addClass(b.sLength);a.aanFeatures.l||(i[0].id=c+"_length");i.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",d[0].outerHTML));h("select",i).val(a._iDisplayLength).bind("change.DT",function(){Ra(a,h(this).val());M(a)});h(a.nTable).bind("length.dt.DT",function(b,c,f){a===c&&h("select",i).val(f)});return i[0]}function sb(a){var b=a.sPaginationType,c=m.ext.pager[b],e="function"===typeof c,d=function(a){M(a)},b=h("<div/>").addClass(a.oClasses.sPaging+b)[0],
+f=a.aanFeatures;e||c.fnInit(a,b,d);f.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(a){if(e){var b=a._iDisplayStart,i=a._iDisplayLength,h=a.fnRecordsDisplay(),l=-1===i,b=l?0:Math.ceil(b/i),i=l?1:Math.ceil(h/i),h=c(b,i),q,l=0;for(q=f.p.length;l<q;l++)Pa(a,"pageButton")(a,f.p[l],l,h,b,i)}else c.fnUpdate(a,d)},sName:"pagination"}));return b}function Ta(a,b,c){var e=a._iDisplayStart,d=a._iDisplayLength,f=a.fnRecordsDisplay();0===f||-1===d?e=0:"number"===typeof b?(e=b*d,e>f&&(e=0)):
+"first"==b?e=0:"previous"==b?(e=0<=d?e-d:0,0>e&&(e=0)):"next"==b?e+d<f&&(e+=d):"last"==b?e=Math.floor((f-1)/d)*d:I(a,0,"Unknown paging action: "+b,5);b=a._iDisplayStart!==e;a._iDisplayStart=e;b&&(w(a,null,"page",[a]),c&&M(a));return b}function pb(a){return h("<div/>",{id:!a.aanFeatures.r?a.sTableId+"_processing":null,"class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function C(a,b){a.oFeatures.bProcessing&&h(a.aanFeatures.r).css("display",b?"block":"none");w(a,
+null,"processing",[a,b])}function qb(a){var b=h(a.nTable);b.attr("role","grid");var c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var e=c.sX,d=c.sY,f=a.oClasses,g=b.children("caption"),j=g.length?g[0]._captionSide:null,i=h(b[0].cloneNode(!1)),o=h(b[0].cloneNode(!1)),l=b.children("tfoot");c.sX&&"100%"===b.attr("width")&&b.removeAttr("width");l.length||(l=null);c=h("<div/>",{"class":f.sScrollWrapper}).append(h("<div/>",{"class":f.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,
+width:e?!e?null:s(e):"100%"}).append(h("<div/>",{"class":f.sScrollHeadInner}).css({"box-sizing":"content-box",width:c.sXInner||"100%"}).append(i.removeAttr("id").css("margin-left",0).append("top"===j?g:null).append(b.children("thead"))))).append(h("<div/>",{"class":f.sScrollBody}).css({overflow:"auto",height:!d?null:s(d),width:!e?null:s(e)}).append(b));l&&c.append(h("<div/>",{"class":f.sScrollFoot}).css({overflow:"hidden",border:0,width:e?!e?null:s(e):"100%"}).append(h("<div/>",{"class":f.sScrollFootInner}).append(o.removeAttr("id").css("margin-left",
+0).append("bottom"===j?g:null).append(b.children("tfoot")))));var b=c.children(),q=b[0],f=b[1],n=l?b[2]:null;if(e)h(f).on("scroll.DT",function(){var a=this.scrollLeft;q.scrollLeft=a;l&&(n.scrollLeft=a)});a.nScrollHead=q;a.nScrollBody=f;a.nScrollFoot=n;a.aoDrawCallback.push({fn:Y,sName:"scrolling"});return c[0]}function Y(a){var b=a.oScroll,c=b.sX,e=b.sXInner,d=b.sY,f=b.iBarWidth,g=h(a.nScrollHead),j=g[0].style,i=g.children("div"),o=i[0].style,l=i.children("table"),i=a.nScrollBody,q=h(i),n=i.style,
+k=h(a.nScrollFoot).children("div"),p=k.children("table"),m=h(a.nTHead),r=h(a.nTable),t=r[0],O=t.style,L=a.nTFoot?h(a.nTFoot):null,ha=a.oBrowser,w=ha.bScrollOversize,v,u,y,x,z,A=[],B=[],C=[],D,E=function(a){a=a.style;a.paddingTop="0";a.paddingBottom="0";a.borderTopWidth="0";a.borderBottomWidth="0";a.height=0};r.children("thead, tfoot").remove();z=m.clone().prependTo(r);v=m.find("tr");y=z.find("tr");z.find("th, td").removeAttr("tabindex");L&&(x=L.clone().prependTo(r),u=L.find("tr"),x=x.find("tr"));
+c||(n.width="100%",g[0].style.width="100%");h.each(qa(a,z),function(b,c){D=la(a,b);c.style.width=a.aoColumns[D].sWidth});L&&G(function(a){a.style.width=""},x);b.bCollapse&&""!==d&&(n.height=q[0].offsetHeight+m[0].offsetHeight+"px");g=r.outerWidth();if(""===c){if(O.width="100%",w&&(r.find("tbody").height()>i.offsetHeight||"scroll"==q.css("overflow-y")))O.width=s(r.outerWidth()-f)}else""!==e?O.width=s(e):g==q.width()&&q.height()<r.height()?(O.width=s(g-f),r.outerWidth()>g-f&&(O.width=s(g))):O.width=
+s(g);g=r.outerWidth();G(E,y);G(function(a){C.push(a.innerHTML);A.push(s(h(a).css("width")))},y);G(function(a,b){a.style.width=A[b]},v);h(y).height(0);L&&(G(E,x),G(function(a){B.push(s(h(a).css("width")))},x),G(function(a,b){a.style.width=B[b]},u),h(x).height(0));G(function(a,b){a.innerHTML='<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+C[b]+"</div>";a.style.width=A[b]},y);L&&G(function(a,b){a.innerHTML="";a.style.width=B[b]},x);if(r.outerWidth()<g){u=i.scrollHeight>i.offsetHeight||
+"scroll"==q.css("overflow-y")?g+f:g;if(w&&(i.scrollHeight>i.offsetHeight||"scroll"==q.css("overflow-y")))O.width=s(u-f);(""===c||""!==e)&&I(a,1,"Possible column misalignment",6)}else u="100%";n.width=s(u);j.width=s(u);L&&(a.nScrollFoot.style.width=s(u));!d&&w&&(n.height=s(t.offsetHeight+f));d&&b.bCollapse&&(n.height=s(d),b=c&&t.offsetWidth>i.offsetWidth?f:0,t.offsetHeight<i.offsetHeight&&(n.height=s(t.offsetHeight+b)));b=r.outerWidth();l[0].style.width=s(b);o.width=s(b);l=r.height()>i.clientHeight||
+"scroll"==q.css("overflow-y");ha="padding"+(ha.bScrollbarLeft?"Left":"Right");o[ha]=l?f+"px":"0px";L&&(p[0].style.width=s(b),k[0].style.width=s(b),k[0].style[ha]=l?f+"px":"0px");q.scroll();if((a.bSorted||a.bFiltered)&&!a._drawHold)i.scrollTop=0}function G(a,b,c){for(var e=0,d=0,f=b.length,g,j;d<f;){g=b[d].firstChild;for(j=c?c[d].firstChild:null;g;)1===g.nodeType&&(c?a(g,j,e):a(g,e),e++),g=g.nextSibling,j=c?j.nextSibling:null;d++}}function Ga(a){var b=a.nTable,c=a.aoColumns,e=a.oScroll,d=e.sY,f=e.sX,
+g=e.sXInner,j=c.length,e=Z(a,"bVisible"),i=h("th",a.nTHead),o=b.getAttribute("width"),l=b.parentNode,k=!1,n,m;(n=b.style.width)&&-1!==n.indexOf("%")&&(o=n);for(n=0;n<e.length;n++)m=c[e[n]],null!==m.sWidth&&(m.sWidth=Db(m.sWidthOrig,l),k=!0);if(!k&&!f&&!d&&j==aa(a)&&j==i.length)for(n=0;n<j;n++)c[n].sWidth=s(i.eq(n).width());else{j=h(b).clone().css("visibility","hidden").removeAttr("id");j.find("tbody tr").remove();var p=h("<tr/>").appendTo(j.find("tbody"));j.find("tfoot th, tfoot td").css("width",
+"");i=qa(a,j.find("thead")[0]);for(n=0;n<e.length;n++)m=c[e[n]],i[n].style.width=null!==m.sWidthOrig&&""!==m.sWidthOrig?s(m.sWidthOrig):"";if(a.aoData.length)for(n=0;n<e.length;n++)k=e[n],m=c[k],h(Eb(a,k)).clone(!1).append(m.sContentPadding).appendTo(p);j.appendTo(l);f&&g?j.width(g):f?(j.css("width","auto"),j.width()<l.offsetWidth&&j.width(l.offsetWidth)):d?j.width(l.offsetWidth):o&&j.width(o);Fb(a,j[0]);if(f){for(n=g=0;n<e.length;n++)m=c[e[n]],d=h(i[n]).outerWidth(),g+=null===m.sWidthOrig?d:parseInt(m.sWidth,
+10)+d-h(i[n]).width();j.width(s(g));b.style.width=s(g)}for(n=0;n<e.length;n++)if(m=c[e[n]],d=h(i[n]).width())m.sWidth=s(d);b.style.width=s(j.css("width"));j.remove()}o&&(b.style.width=s(o));if((o||f)&&!a._reszEvt)b=function(){h(Ea).bind("resize.DT-"+a.sInstance,ua(function(){X(a)}))},a.oBrowser.bScrollOversize?setTimeout(b,1E3):b(),a._reszEvt=!0}function ua(a,b){var c=b!==k?b:200,e,d;return function(){var b=this,g=+new Date,j=arguments;e&&g<e+c?(clearTimeout(d),d=setTimeout(function(){e=k;a.apply(b,
+j)},c)):(e=g,a.apply(b,j))}}function Db(a,b){if(!a)return 0;var c=h("<div/>").css("width",s(a)).appendTo(b||Q.body),e=c[0].offsetWidth;c.remove();return e}function Fb(a,b){var c=a.oScroll;if(c.sX||c.sY)c=!c.sX?c.iBarWidth:0,b.style.width=s(h(b).outerWidth()-c)}function Eb(a,b){var c=Gb(a,b);if(0>c)return null;var e=a.aoData[c];return!e.nTr?h("<td/>").html(x(a,c,b,"display"))[0]:e.anCells[b]}function Gb(a,b){for(var c,e=-1,d=-1,f=0,g=a.aoData.length;f<g;f++)c=x(a,f,b,"display")+"",c=c.replace($b,""),
+c.length>e&&(e=c.length,d=f);return d}function s(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function Hb(){var a=m.__scrollbarWidth;if(a===k){var b=h("<p/>").css({position:"absolute",top:0,left:0,width:"100%",height:150,padding:0,overflow:"scroll",visibility:"hidden"}).appendTo("body"),a=b[0].offsetWidth-b[0].clientWidth;m.__scrollbarWidth=a;b.remove()}return a}function U(a){var b,c,e=[],d=a.aoColumns,f,g,j,i;b=a.aaSortingFixed;c=h.isPlainObject(b);var o=[];
+f=function(a){a.length&&!h.isArray(a[0])?o.push(a):o.push.apply(o,a)};h.isArray(b)&&f(b);c&&b.pre&&f(b.pre);f(a.aaSorting);c&&b.post&&f(b.post);for(a=0;a<o.length;a++){i=o[a][0];f=d[i].aDataSort;b=0;for(c=f.length;b<c;b++)g=f[b],j=d[g].sType||"string",o[a]._idx===k&&(o[a]._idx=h.inArray(o[a][1],d[g].asSorting)),e.push({src:i,col:g,dir:o[a][1],index:o[a]._idx,type:j,formatter:m.ext.type.order[j+"-pre"]})}return e}function lb(a){var b,c,e=[],d=m.ext.type.order,f=a.aoData,g=0,j,i=a.aiDisplayMaster,h;
+Ha(a);h=U(a);b=0;for(c=h.length;b<c;b++)j=h[b],j.formatter&&g++,Ib(a,j.col);if("ssp"!=B(a)&&0!==h.length){b=0;for(c=i.length;b<c;b++)e[i[b]]=b;g===h.length?i.sort(function(a,b){var c,d,g,j,i=h.length,k=f[a]._aSortData,m=f[b]._aSortData;for(g=0;g<i;g++)if(j=h[g],c=k[j.col],d=m[j.col],c=c<d?-1:c>d?1:0,0!==c)return"asc"===j.dir?c:-c;c=e[a];d=e[b];return c<d?-1:c>d?1:0}):i.sort(function(a,b){var c,g,j,i,k=h.length,m=f[a]._aSortData,r=f[b]._aSortData;for(j=0;j<k;j++)if(i=h[j],c=m[i.col],g=r[i.col],i=d[i.type+
+"-"+i.dir]||d["string-"+i.dir],c=i(c,g),0!==c)return c;c=e[a];g=e[b];return c<g?-1:c>g?1:0})}a.bSorted=!0}function Jb(a){for(var b,c,e=a.aoColumns,d=U(a),a=a.oLanguage.oAria,f=0,g=e.length;f<g;f++){c=e[f];var j=c.asSorting;b=c.sTitle.replace(/<.*?>/g,"");var i=c.nTh;i.removeAttribute("aria-sort");c.bSortable&&(0<d.length&&d[0].col==f?(i.setAttribute("aria-sort","asc"==d[0].dir?"ascending":"descending"),c=j[d[0].index+1]||j[0]):c=j[0],b+="asc"===c?a.sSortAscending:a.sSortDescending);i.setAttribute("aria-label",
+b)}}function Ua(a,b,c,e){var d=a.aaSorting,f=a.aoColumns[b].asSorting,g=function(a,b){var c=a._idx;c===k&&(c=h.inArray(a[1],f));return c+1<f.length?c+1:b?null:0};"number"===typeof d[0]&&(d=a.aaSorting=[d]);c&&a.oFeatures.bSortMulti?(c=h.inArray(b,D(d,"0")),-1!==c?(b=g(d[c],!0),null===b&&1===d.length&&(b=0),null===b?d.splice(c,1):(d[c][1]=f[b],d[c]._idx=b)):(d.push([b,f[0],0]),d[d.length-1]._idx=0)):d.length&&d[0][0]==b?(b=g(d[0]),d.length=1,d[0][1]=f[b],d[0]._idx=b):(d.length=0,d.push([b,f[0]]),d[0]._idx=
+0);N(a);"function"==typeof e&&e(a)}function Oa(a,b,c,e){var d=a.aoColumns[c];Va(b,{},function(b){!1!==d.bSortable&&(a.oFeatures.bProcessing?(C(a,!0),setTimeout(function(){Ua(a,c,b.shiftKey,e);"ssp"!==B(a)&&C(a,!1)},0)):Ua(a,c,b.shiftKey,e))})}function xa(a){var b=a.aLastSort,c=a.oClasses.sSortColumn,e=U(a),d=a.oFeatures,f,g;if(d.bSort&&d.bSortClasses){d=0;for(f=b.length;d<f;d++)g=b[d].src,h(D(a.aoData,"anCells",g)).removeClass(c+(2>d?d+1:3));d=0;for(f=e.length;d<f;d++)g=e[d].src,h(D(a.aoData,"anCells",
+g)).addClass(c+(2>d?d+1:3))}a.aLastSort=e}function Ib(a,b){var c=a.aoColumns[b],e=m.ext.order[c.sSortDataType],d;e&&(d=e.call(a.oInstance,a,b,$(a,b)));for(var f,g=m.ext.type.order[c.sType+"-pre"],j=0,i=a.aoData.length;j<i;j++)if(c=a.aoData[j],c._aSortData||(c._aSortData=[]),!c._aSortData[b]||e)f=e?d[j]:x(a,j,b,"sort"),c._aSortData[b]=g?g(f):f}function ya(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b={time:+new Date,start:a._iDisplayStart,length:a._iDisplayLength,order:h.extend(!0,[],a.aaSorting),
+search:zb(a.oPreviousSearch),columns:h.map(a.aoColumns,function(b,e){return{visible:b.bVisible,search:zb(a.aoPreSearchCols[e])}})};w(a,"aoStateSaveParams","stateSaveParams",[a,b]);a.oSavedState=b;a.fnStateSaveCallback.call(a.oInstance,a,b)}}function Kb(a){var b,c,e=a.aoColumns;if(a.oFeatures.bStateSave){var d=a.fnStateLoadCallback.call(a.oInstance,a);if(d&&d.time&&(b=w(a,"aoStateLoadParams","stateLoadParams",[a,d]),-1===h.inArray(!1,b)&&(b=a.iStateDuration,!(0<b&&d.time<+new Date-1E3*b)&&e.length===
+d.columns.length))){a.oLoadedState=h.extend(!0,{},d);d.start!==k&&(a._iDisplayStart=d.start,a.iInitDisplayStart=d.start);d.length!==k&&(a._iDisplayLength=d.length);d.order!==k&&(a.aaSorting=[],h.each(d.order,function(b,c){a.aaSorting.push(c[0]>=e.length?[0,c[1]]:c)}));d.search!==k&&h.extend(a.oPreviousSearch,Ab(d.search));b=0;for(c=d.columns.length;b<c;b++){var f=d.columns[b];f.visible!==k&&(e[b].bVisible=f.visible);f.search!==k&&h.extend(a.aoPreSearchCols[b],Ab(f.search))}w(a,"aoStateLoaded","stateLoaded",
+[a,d])}}}function za(a){var b=m.settings,a=h.inArray(a,D(b,"nTable"));return-1!==a?b[a]:null}function I(a,b,c,e){c="DataTables warning: "+(null!==a?"table id="+a.sTableId+" - ":"")+c;e&&(c+=". For more information about this error, please see http://datatables.net/tn/"+e);if(b)Ea.console&&console.log&&console.log(c);else if(b=m.ext,b=b.sErrMode||b.errMode,w(a,null,"error",[a,e,c]),"alert"==b)alert(c);else{if("throw"==b)throw Error(c);"function"==typeof b&&b(a,e,c)}}function E(a,b,c,e){h.isArray(c)?
+h.each(c,function(c,f){h.isArray(f)?E(a,b,f[0],f[1]):E(a,b,f)}):(e===k&&(e=c),b[c]!==k&&(a[e]=b[c]))}function Lb(a,b,c){var e,d;for(d in b)b.hasOwnProperty(d)&&(e=b[d],h.isPlainObject(e)?(h.isPlainObject(a[d])||(a[d]={}),h.extend(!0,a[d],e)):a[d]=c&&"data"!==d&&"aaData"!==d&&h.isArray(e)?e.slice():e);return a}function Va(a,b,c){h(a).bind("click.DT",b,function(b){a.blur();c(b)}).bind("keypress.DT",b,function(a){13===a.which&&(a.preventDefault(),c(a))}).bind("selectstart.DT",function(){return!1})}function z(a,
+b,c,e){c&&a[b].push({fn:c,sName:e})}function w(a,b,c,e){var d=[];b&&(d=h.map(a[b].slice().reverse(),function(b){return b.fn.apply(a.oInstance,e)}));null!==c&&(b=h.Event(c+".dt"),h(a.nTable).trigger(b,e),d.push(b.result));return d}function Sa(a){var b=a._iDisplayStart,c=a.fnDisplayEnd(),e=a._iDisplayLength;b>=c&&(b=c-e);b-=b%e;if(-1===e||0>b)b=0;a._iDisplayStart=b}function Pa(a,b){var c=a.renderer,e=m.ext.renderer[b];return h.isPlainObject(c)&&c[b]?e[c[b]]||e._:"string"===typeof c?e[c]||e._:e._}function B(a){return a.oFeatures.bServerSide?
+"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function Wa(a,b){var c=[],c=Mb.numbers_length,e=Math.floor(c/2);b<=c?c=V(0,b):a<=e?(c=V(0,c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-e?c=V(b-(c-2),b):(c=V(a-e+2,a+e-1),c.push("ellipsis"),c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function db(a){h.each({num:function(b){return Aa(b,a)},"num-fmt":function(b){return Aa(b,a,Xa)},"html-num":function(b){return Aa(b,a,Ba)},"html-num-fmt":function(b){return Aa(b,a,Ba,Xa)}},function(b,
+c){u.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(u.type.search[b+a]=u.type.search.html)})}function Nb(a){return function(){var b=[za(this[m.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return m.ext.internal[a].apply(this,b)}}var m,u,t,r,v,Ya={},Ob=/[\r\n]/g,Ba=/<.*?>/g,ac=/^[\w\+\-]/,bc=/[\w\+\-]$/,Yb=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"),Xa=/[',$\u00a3\u20ac\u00a5%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi,J=function(a){return!a||!0===a||
+"-"===a?!0:!1},Pb=function(a){var b=parseInt(a,10);return!isNaN(b)&&isFinite(a)?b:null},Qb=function(a,b){Ya[b]||(Ya[b]=RegExp(va(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace(Ya[b],"."):a},Za=function(a,b,c){var e="string"===typeof a;if(J(a))return!0;b&&e&&(a=Qb(a,b));c&&e&&(a=a.replace(Xa,""));return!isNaN(parseFloat(a))&&isFinite(a)},Rb=function(a,b,c){return J(a)?!0:!(J(a)||"string"===typeof a)?null:Za(a.replace(Ba,""),b,c)?!0:null},D=function(a,b,c){var e=[],d=0,f=a.length;
+if(c!==k)for(;d<f;d++)a[d]&&a[d][b]&&e.push(a[d][b][c]);else for(;d<f;d++)a[d]&&e.push(a[d][b]);return e},ia=function(a,b,c,e){var d=[],f=0,g=b.length;if(e!==k)for(;f<g;f++)a[b[f]][c]&&d.push(a[b[f]][c][e]);else for(;f<g;f++)d.push(a[b[f]][c]);return d},V=function(a,b){var c=[],e;b===k?(b=0,e=a):(e=b,b=a);for(var d=b;d<e;d++)c.push(d);return c},Sb=function(a){for(var b=[],c=0,e=a.length;c<e;c++)a[c]&&b.push(a[c]);return b},Na=function(a){var b=[],c,e,d=a.length,f,g=0;e=0;a:for(;e<d;e++){c=a[e];for(f=
+0;f<g;f++)if(b[f]===c)continue a;b.push(c);g++}return b},A=function(a,b,c){a[b]!==k&&(a[c]=a[b])},ba=/\[.*?\]$/,T=/\(\)$/,wa=h("<div>")[0],Zb=wa.textContent!==k,$b=/<.*?>/g;m=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new t(za(this[u.iApiIndex])):new t(this)};this.fnAddData=function(a,b){var c=this.api(!0),e=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===
+k||b)&&c.draw();return e.flatten().toArray()};this.fnAdjustColumnSizing=function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],e=c.oScroll;a===k||a?b.draw(!1):(""!==e.sX||""!==e.sY)&&Y(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===k||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var e=this.api(!0),a=e.rows(a),d=a.settings()[0],h=d.aoData[a[0][0]];a.remove();b&&b.call(this,d,h);(c===k||c)&&e.draw();return h};
+this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(a)};this.fnFilter=function(a,b,c,e,d,h){d=this.api(!0);null===b||b===k?d.search(a,c,e,h):d.column(b).search(a,c,e,h);d.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==k){var e=a.nodeName?a.nodeName.toLowerCase():"";return b!==k||"td"==e||"th"==e?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==k?b.row(a).node():b.rows().nodes().flatten().toArray()};
+this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase();return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),[a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===k||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===
+k||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return za(this[u.iApiIndex])};this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,e,d){var h=this.api(!0);c===k||null===c?h.row(b).data(a):h.cell(b,c).data(a);(d===k||d)&&h.columns.adjust();(e===k||e)&&h.draw();return 0};this.fnVersionCheck=u.fnVersionCheck;var b=this,c=a===k,e=this.length;c&&(a={});this.oApi=this.internal=u.internal;for(var d in m.ext.internal)d&&
+(this[d]=Nb(d));this.each(function(){var d={},d=1<e?Lb(d,a,!0):a,g=0,j,i=this.getAttribute("id"),o=!1,l=m.defaults,q=h(this);if("table"!=this.nodeName.toLowerCase())I(null,0,"Non-table node initialisation ("+this.nodeName+")",2);else{eb(l);fb(l.column);H(l,l,!0);H(l.column,l.column,!0);H(l,h.extend(d,q.data()));var n=m.settings,g=0;for(j=n.length;g<j;g++){var r=n[g];if(r.nTable==this||r.nTHead.parentNode==this||r.nTFoot&&r.nTFoot.parentNode==this){g=d.bRetrieve!==k?d.bRetrieve:l.bRetrieve;if(c||g)return r.oInstance;
+if(d.bDestroy!==k?d.bDestroy:l.bDestroy){r.oInstance.fnDestroy();break}else{I(r,0,"Cannot reinitialise DataTable",3);return}}if(r.sTableId==this.id){n.splice(g,1);break}}if(null===i||""===i)this.id=i="DataTables_Table_"+m.ext._unique++;var p=h.extend(!0,{},m.models.oSettings,{sDestroyWidth:q[0].style.width,sInstance:i,sTableId:i});p.nTable=this;p.oApi=b.internal;p.oInit=d;n.push(p);p.oInstance=1===b.length?b:q.dataTable();eb(d);d.oLanguage&&P(d.oLanguage);d.aLengthMenu&&!d.iDisplayLength&&(d.iDisplayLength=
+h.isArray(d.aLengthMenu[0])?d.aLengthMenu[0][0]:d.aLengthMenu[0]);d=Lb(h.extend(!0,{},l),d);E(p.oFeatures,d,"bPaginate bLengthChange bFilter bSort bSortMulti bInfo bProcessing bAutoWidth bSortClasses bServerSide bDeferRender".split(" "));E(p,d,["asStripeClasses","ajax","fnServerData","fnFormatNumber","sServerMethod","aaSorting","aaSortingFixed","aLengthMenu","sPaginationType","sAjaxSource","sAjaxDataProp","iStateDuration","sDom","bSortCellsTop","iTabIndex","fnStateLoadCallback","fnStateSaveCallback",
+"renderer","searchDelay",["iCookieDuration","iStateDuration"],["oSearch","oPreviousSearch"],["aoSearchCols","aoPreSearchCols"],["iDisplayLength","_iDisplayLength"],["bJQueryUI","bJUI"]]);E(p.oScroll,d,[["sScrollX","sX"],["sScrollXInner","sXInner"],["sScrollY","sY"],["bScrollCollapse","bCollapse"]]);E(p.oLanguage,d,"fnInfoCallback");z(p,"aoDrawCallback",d.fnDrawCallback,"user");z(p,"aoServerParams",d.fnServerParams,"user");z(p,"aoStateSaveParams",d.fnStateSaveParams,"user");z(p,"aoStateLoadParams",
+d.fnStateLoadParams,"user");z(p,"aoStateLoaded",d.fnStateLoaded,"user");z(p,"aoRowCallback",d.fnRowCallback,"user");z(p,"aoRowCreatedCallback",d.fnCreatedRow,"user");z(p,"aoHeaderCallback",d.fnHeaderCallback,"user");z(p,"aoFooterCallback",d.fnFooterCallback,"user");z(p,"aoInitComplete",d.fnInitComplete,"user");z(p,"aoPreDrawCallback",d.fnPreDrawCallback,"user");i=p.oClasses;d.bJQueryUI?(h.extend(i,m.ext.oJUIClasses,d.oClasses),d.sDom===l.sDom&&"lfrtip"===l.sDom&&(p.sDom='<"H"lfr>t<"F"ip>'),p.renderer)?
+h.isPlainObject(p.renderer)&&!p.renderer.header&&(p.renderer.header="jqueryui"):p.renderer="jqueryui":h.extend(i,m.ext.classes,d.oClasses);q.addClass(i.sTable);if(""!==p.oScroll.sX||""!==p.oScroll.sY)p.oScroll.iBarWidth=Hb();!0===p.oScroll.sX&&(p.oScroll.sX="100%");p.iInitDisplayStart===k&&(p.iInitDisplayStart=d.iDisplayStart,p._iDisplayStart=d.iDisplayStart);null!==d.iDeferLoading&&(p.bDeferLoading=!0,g=h.isArray(d.iDeferLoading),p._iRecordsDisplay=g?d.iDeferLoading[0]:d.iDeferLoading,p._iRecordsTotal=
+g?d.iDeferLoading[1]:d.iDeferLoading);var t=p.oLanguage;h.extend(!0,t,d.oLanguage);""!==t.sUrl&&(h.ajax({dataType:"json",url:t.sUrl,success:function(a){P(a);H(l.oLanguage,a);h.extend(true,t,a);ga(p)},error:function(){ga(p)}}),o=!0);null===d.asStripeClasses&&(p.asStripeClasses=[i.sStripeOdd,i.sStripeEven]);var g=p.asStripeClasses,s=q.children("tbody").find("tr").eq(0);-1!==h.inArray(!0,h.map(g,function(a){return s.hasClass(a)}))&&(h("tbody tr",this).removeClass(g.join(" ")),p.asDestroyStripes=g.slice());
+n=[];g=this.getElementsByTagName("thead");0!==g.length&&(da(p.aoHeader,g[0]),n=qa(p));if(null===d.aoColumns){r=[];g=0;for(j=n.length;g<j;g++)r.push(null)}else r=d.aoColumns;g=0;for(j=r.length;g<j;g++)Fa(p,n?n[g]:null);ib(p,d.aoColumnDefs,r,function(a,b){ka(p,a,b)});if(s.length){var u=function(a,b){return a.getAttribute("data-"+b)!==null?b:null};h.each(na(p,s[0]).cells,function(a,b){var c=p.aoColumns[a];if(c.mData===a){var d=u(b,"sort")||u(b,"order"),e=u(b,"filter")||u(b,"search");if(d!==null||e!==
+null){c.mData={_:a+".display",sort:d!==null?a+".@data-"+d:k,type:d!==null?a+".@data-"+d:k,filter:e!==null?a+".@data-"+e:k};ka(p,a)}}})}var v=p.oFeatures;d.bStateSave&&(v.bStateSave=!0,Kb(p,d),z(p,"aoDrawCallback",ya,"state_save"));if(d.aaSorting===k){n=p.aaSorting;g=0;for(j=n.length;g<j;g++)n[g][1]=p.aoColumns[g].asSorting[0]}xa(p);v.bSort&&z(p,"aoDrawCallback",function(){if(p.bSorted){var a=U(p),b={};h.each(a,function(a,c){b[c.src]=c.dir});w(p,null,"order",[p,a,b]);Jb(p)}});z(p,"aoDrawCallback",
+function(){(p.bSorted||B(p)==="ssp"||v.bDeferRender)&&xa(p)},"sc");gb(p);g=q.children("caption").each(function(){this._captionSide=q.css("caption-side")});j=q.children("thead");0===j.length&&(j=h("<thead/>").appendTo(this));p.nTHead=j[0];j=q.children("tbody");0===j.length&&(j=h("<tbody/>").appendTo(this));p.nTBody=j[0];j=q.children("tfoot");if(0===j.length&&0<g.length&&(""!==p.oScroll.sX||""!==p.oScroll.sY))j=h("<tfoot/>").appendTo(this);0===j.length||0===j.children().length?q.addClass(i.sNoFooter):
+0<j.length&&(p.nTFoot=j[0],da(p.aoFooter,p.nTFoot));if(d.aaData)for(g=0;g<d.aaData.length;g++)K(p,d.aaData[g]);else(p.bDeferLoading||"dom"==B(p))&&ma(p,h(p.nTBody).children("tr"));p.aiDisplay=p.aiDisplayMaster.slice();p.bInitialised=!0;!1===o&&ga(p)}});b=null;return this};var Tb=[],y=Array.prototype,cc=function(a){var b,c,e=m.settings,d=h.map(e,function(a){return a.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase())return b=h.inArray(a,d),-1!==b?[e[b]]:
+null;if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?c=h(a):a instanceof h&&(c=a)}else return[];if(c)return c.map(function(){b=h.inArray(this,d);return-1!==b?e[b]:null}).toArray()};t=function(a,b){if(!(this instanceof t))return new t(a,b);var c=[],e=function(a){(a=cc(a))&&c.push.apply(c,a)};if(h.isArray(a))for(var d=0,f=a.length;d<f;d++)e(a[d]);else e(a);this.context=Na(c);b&&this.push.apply(this,b.toArray?b.toArray():b);this.selector={rows:null,cols:null,opts:null};
+t.extend(this,this,Tb)};m.Api=t;t.prototype={any:function(){return 0!==this.flatten().length},concat:y.concat,context:[],each:function(a){for(var b=0,c=this.length;b<c;b++)a.call(this,this[b],b,this);return this},eq:function(a){var b=this.context;return b.length>a?new t(b[a],this[a]):null},filter:function(a){var b=[];if(y.filter)b=y.filter.call(this,a,this);else for(var c=0,e=this.length;c<e;c++)a.call(this,this[c],c,this)&&b.push(this[c]);return new t(this.context,b)},flatten:function(){var a=[];
+return new t(this.context,a.concat.apply(a,this.toArray()))},join:y.join,indexOf:y.indexOf||function(a,b){for(var c=b||0,e=this.length;c<e;c++)if(this[c]===a)return c;return-1},iterator:function(a,b,c,e){var d=[],f,g,h,i,o,l=this.context,q,n,m=this.selector;"string"===typeof a&&(e=c,c=b,b=a,a=!1);g=0;for(h=l.length;g<h;g++){var p=new t(l[g]);if("table"===b)f=c.call(p,l[g],g),f!==k&&d.push(f);else if("columns"===b||"rows"===b)f=c.call(p,l[g],this[g],g),f!==k&&d.push(f);else if("column"===b||"column-rows"===
+b||"row"===b||"cell"===b){n=this[g];"column-rows"===b&&(q=Ca(l[g],m.opts));i=0;for(o=n.length;i<o;i++)f=n[i],f="cell"===b?c.call(p,l[g],f.row,f.column,g,i):c.call(p,l[g],f,g,i,q),f!==k&&d.push(f)}}return d.length||e?(a=new t(l,a?d.concat.apply([],d):d),b=a.selector,b.rows=m.rows,b.cols=m.cols,b.opts=m.opts,a):this},lastIndexOf:y.lastIndexOf||function(a,b){return this.indexOf.apply(this.toArray.reverse(),arguments)},length:0,map:function(a){var b=[];if(y.map)b=y.map.call(this,a,this);else for(var c=
+0,e=this.length;c<e;c++)b.push(a.call(this,this[c],c));return new t(this.context,b)},pluck:function(a){return this.map(function(b){return b[a]})},pop:y.pop,push:y.push,reduce:y.reduce||function(a,b){return hb(this,a,b,0,this.length,1)},reduceRight:y.reduceRight||function(a,b){return hb(this,a,b,this.length-1,-1,-1)},reverse:y.reverse,selector:null,shift:y.shift,sort:y.sort,splice:y.splice,toArray:function(){return y.slice.call(this)},to$:function(){return h(this)},toJQuery:function(){return h(this)},
+unique:function(){return new t(this.context,Na(this))},unshift:y.unshift};t.extend=function(a,b,c){if(c.length&&b&&(b instanceof t||b.__dt_wrapper)){var e,d,f,g=function(a,b,c){return function(){var d=b.apply(a,arguments);t.extend(d,d,c.methodExt);return d}};e=0;for(d=c.length;e<d;e++)f=c[e],b[f.name]="function"===typeof f.val?g(a,f.val,f):h.isPlainObject(f.val)?{}:f.val,b[f.name].__dt_wrapper=!0,t.extend(a,b[f.name],f.propExt)}};t.register=r=function(a,b){if(h.isArray(a))for(var c=0,e=a.length;c<
+e;c++)t.register(a[c],b);else for(var d=a.split("."),f=Tb,g,j,c=0,e=d.length;c<e;c++){g=(j=-1!==d[c].indexOf("()"))?d[c].replace("()",""):d[c];var i;a:{i=0;for(var o=f.length;i<o;i++)if(f[i].name===g){i=f[i];break a}i=null}i||(i={name:g,val:{},methodExt:[],propExt:[]},f.push(i));c===e-1?i.val=b:f=j?i.methodExt:i.propExt}};t.registerPlural=v=function(a,b,c){t.register(a,c);t.register(b,function(){var a=c.apply(this,arguments);return a===this?this:a instanceof t?a.length?h.isArray(a[0])?new t(a.context,
+a[0]):a[0]:k:a})};r("tables()",function(a){var b;if(a){b=t;var c=this.context;if("number"===typeof a)a=[c[a]];else var e=h.map(c,function(a){return a.nTable}),a=h(e).filter(a).map(function(){var a=h.inArray(this,e);return c[a]}).toArray();b=new b(a)}else b=this;return b});r("table()",function(a){var a=this.tables(a),b=a.context;return b.length?new t(b[0]):a});v("tables().nodes()","table().node()",function(){return this.iterator("table",function(a){return a.nTable},1)});v("tables().body()","table().body()",
+function(){return this.iterator("table",function(a){return a.nTBody},1)});v("tables().header()","table().header()",function(){return this.iterator("table",function(a){return a.nTHead},1)});v("tables().footer()","table().footer()",function(){return this.iterator("table",function(a){return a.nTFoot},1)});v("tables().containers()","table().container()",function(){return this.iterator("table",function(a){return a.nTableWrapper},1)});r("draw()",function(a){return this.iterator("table",function(b){N(b,
+!1===a)})});r("page()",function(a){return a===k?this.page.info().page:this.iterator("table",function(b){Ta(b,a)})});r("page.info()",function(){if(0===this.context.length)return k;var a=this.context[0],b=a._iDisplayStart,c=a._iDisplayLength,e=a.fnRecordsDisplay(),d=-1===c;return{page:d?0:Math.floor(b/c),pages:d?1:Math.ceil(e/c),start:b,end:a.fnDisplayEnd(),length:c,recordsTotal:a.fnRecordsTotal(),recordsDisplay:e}});r("page.len()",function(a){return a===k?0!==this.context.length?this.context[0]._iDisplayLength:
+k:this.iterator("table",function(b){Ra(b,a)})});var Ub=function(a,b,c){if(c){var e=new t(a);e.one("draw",function(){c(e.ajax.json())})}"ssp"==B(a)?N(a,b):(C(a,!0),ra(a,[],function(c){oa(a);for(var c=sa(a,c),e=0,g=c.length;e<g;e++)K(a,c[e]);N(a,b);C(a,!1)}))};r("ajax.json()",function(){var a=this.context;if(0<a.length)return a[0].json});r("ajax.params()",function(){var a=this.context;if(0<a.length)return a[0].oAjaxData});r("ajax.reload()",function(a,b){return this.iterator("table",function(c){Ub(c,
+!1===b,a)})});r("ajax.url()",function(a){var b=this.context;if(a===k){if(0===b.length)return k;b=b[0];return b.ajax?h.isPlainObject(b.ajax)?b.ajax.url:b.ajax:b.sAjaxSource}return this.iterator("table",function(b){h.isPlainObject(b.ajax)?b.ajax.url=a:b.ajax=a})});r("ajax.url().load()",function(a,b){return this.iterator("table",function(c){Ub(c,!1===b,a)})});var $a=function(a,b,c,e,d){var f=[],g,j,i,o,l,q;i=typeof b;if(!b||"string"===i||"function"===i||b.length===k)b=[b];i=0;for(o=b.length;i<o;i++){j=
+b[i]&&b[i].split?b[i].split(","):[b[i]];l=0;for(q=j.length;l<q;l++)(g=c("string"===typeof j[l]?h.trim(j[l]):j[l]))&&g.length&&f.push.apply(f,g)}a=u.selector[a];if(a.length){i=0;for(o=a.length;i<o;i++)f=a[i](e,d,f)}return f},ab=function(a){a||(a={});a.filter&&a.search===k&&(a.search=a.filter);return h.extend({search:"none",order:"current",page:"all"},a)},bb=function(a){for(var b=0,c=a.length;b<c;b++)if(0<a[b].length)return a[0]=a[b],a[0].length=1,a.length=1,a.context=[a.context[b]],a;a.length=0;return a},
+Ca=function(a,b){var c,e,d,f=[],g=a.aiDisplay;c=a.aiDisplayMaster;var j=b.search;e=b.order;d=b.page;if("ssp"==B(a))return"removed"===j?[]:V(0,c.length);if("current"==d){c=a._iDisplayStart;for(e=a.fnDisplayEnd();c<e;c++)f.push(g[c])}else if("current"==e||"applied"==e)f="none"==j?c.slice():"applied"==j?g.slice():h.map(c,function(a){return-1===h.inArray(a,g)?a:null});else if("index"==e||"original"==e){c=0;for(e=a.aoData.length;c<e;c++)"none"==j?f.push(c):(d=h.inArray(c,g),(-1===d&&"removed"==j||0<=d&&
+"applied"==j)&&f.push(c))}return f};r("rows()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=ab(b),c=this.iterator("table",function(c){var d=b;return $a("row",a,function(a){var b=Pb(a);if(b!==null&&!d)return[b];var j=Ca(c,d);if(b!==null&&h.inArray(b,j)!==-1)return[b];if(!a)return j;if(typeof a==="function")return h.map(j,function(b){var d=c.aoData[b];return a(b,d._aData,d.nTr)?b:null});b=Sb(ia(c.aoData,j,"nTr"));return a.nodeName&&h.inArray(a,b)!==-1?[a._DT_RowIndex]:h(b).filter(a).map(function(){return this._DT_RowIndex}).toArray()},
+c,d)},1);c.selector.rows=a;c.selector.opts=b;return c});r("rows().nodes()",function(){return this.iterator("row",function(a,b){return a.aoData[b].nTr||k},1)});r("rows().data()",function(){return this.iterator(!0,"rows",function(a,b){return ia(a.aoData,b,"_aData")},1)});v("rows().cache()","row().cache()",function(a){return this.iterator("row",function(b,c){var e=b.aoData[c];return"search"===a?e._aFilterData:e._aSortData},1)});v("rows().invalidate()","row().invalidate()",function(a){return this.iterator("row",
+function(b,c){ca(b,c,a)})});v("rows().indexes()","row().index()",function(){return this.iterator("row",function(a,b){return b},1)});v("rows().remove()","row().remove()",function(){var a=this;return this.iterator("row",function(b,c,e){var d=b.aoData;d.splice(c,1);for(var f=0,g=d.length;f<g;f++)null!==d[f].nTr&&(d[f].nTr._DT_RowIndex=f);h.inArray(c,b.aiDisplay);pa(b.aiDisplayMaster,c);pa(b.aiDisplay,c);pa(a[e],c,!1);Sa(b)})});r("rows.add()",function(a){var b=this.iterator("table",function(b){var c,
+f,g,h=[];f=0;for(g=a.length;f<g;f++)c=a[f],c.nodeName&&"TR"===c.nodeName.toUpperCase()?h.push(ma(b,c)[0]):h.push(K(b,c));return h},1),c=this.rows(-1);c.pop();c.push.apply(c,b.toArray());return c});r("row()",function(a,b){return bb(this.rows(a,b))});r("row().data()",function(a){var b=this.context;if(a===k)return b.length&&this.length?b[0].aoData[this[0]]._aData:k;b[0].aoData[this[0]]._aData=a;ca(b[0],this[0],"data");return this});r("row().node()",function(){var a=this.context;return a.length&&this.length?
+a[0].aoData[this[0]].nTr||null:null});r("row.add()",function(a){a instanceof h&&a.length&&(a=a[0]);var b=this.iterator("table",function(b){return a.nodeName&&"TR"===a.nodeName.toUpperCase()?ma(b,a)[0]:K(b,a)});return this.row(b[0])});var cb=function(a,b){var c=a.context;c.length&&(c=c[0].aoData[b!==k?b:a[0]],c._details&&(c._details.remove(),c._detailsShow=k,c._details=k))},Vb=function(a,b){var c=a.context;if(c.length&&a.length){var e=c[0].aoData[a[0]];if(e._details){(e._detailsShow=b)?e._details.insertAfter(e.nTr):
+e._details.detach();var d=c[0],f=new t(d),g=d.aoData;f.off("draw.dt.DT_details column-visibility.dt.DT_details destroy.dt.DT_details");0<D(g,"_details").length&&(f.on("draw.dt.DT_details",function(a,b){d===b&&f.rows({page:"current"}).eq(0).each(function(a){a=g[a];a._detailsShow&&a._details.insertAfter(a.nTr)})}),f.on("column-visibility.dt.DT_details",function(a,b){if(d===b)for(var c,e=aa(b),f=0,h=g.length;f<h;f++)c=g[f],c._details&&c._details.children("td[colspan]").attr("colspan",e)}),f.on("destroy.dt.DT_details",
+function(a,b){if(d===b)for(var c=0,e=g.length;c<e;c++)g[c]._details&&cb(f,c)}))}}};r("row().child()",function(a,b){var c=this.context;if(a===k)return c.length&&this.length?c[0].aoData[this[0]]._details:k;if(!0===a)this.child.show();else if(!1===a)cb(this);else if(c.length&&this.length){var e=c[0],c=c[0].aoData[this[0]],d=[],f=function(a,b){if(h.isArray(a)||a instanceof h)for(var c=0,k=a.length;c<k;c++)f(a[c],b);else a.nodeName&&"tr"===a.nodeName.toLowerCase()?d.push(a):(c=h("<tr><td/></tr>").addClass(b),
+h("td",c).addClass(b).html(a)[0].colSpan=aa(e),d.push(c[0]))};f(a,b);c._details&&c._details.remove();c._details=h(d);c._detailsShow&&c._details.insertAfter(c.nTr)}return this});r(["row().child.show()","row().child().show()"],function(){Vb(this,!0);return this});r(["row().child.hide()","row().child().hide()"],function(){Vb(this,!1);return this});r(["row().child.remove()","row().child().remove()"],function(){cb(this);return this});r("row().child.isShown()",function(){var a=this.context;return a.length&&
+this.length?a[0].aoData[this[0]]._detailsShow||!1:!1});var dc=/^(.+):(name|visIdx|visible)$/,Wb=function(a,b,c,e,d){for(var c=[],e=0,f=d.length;e<f;e++)c.push(x(a,d[e],b));return c};r("columns()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=ab(b),c=this.iterator("table",function(c){var d=a,f=b,g=c.aoColumns,j=D(g,"sName"),i=D(g,"nTh");return $a("column",d,function(a){var b=Pb(a);if(a==="")return V(g.length);if(b!==null)return[b>=0?b:g.length+b];if(typeof a==="function"){var d=Ca(c,
+f);return h.map(g,function(b,f){return a(f,Wb(c,f,0,0,d),i[f])?f:null})}var k=typeof a==="string"?a.match(dc):"";if(k)switch(k[2]){case "visIdx":case "visible":b=parseInt(k[1],10);if(b<0){var m=h.map(g,function(a,b){return a.bVisible?b:null});return[m[m.length+b]]}return[la(c,b)];case "name":return h.map(j,function(a,b){return a===k[1]?b:null})}else return h(i).filter(a).map(function(){return h.inArray(this,i)}).toArray()},c,f)},1);c.selector.cols=a;c.selector.opts=b;return c});v("columns().header()",
+"column().header()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTh},1)});v("columns().footer()","column().footer()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTf},1)});v("columns().data()","column().data()",function(){return this.iterator("column-rows",Wb,1)});v("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});v("columns().cache()","column().cache()",
+function(a){return this.iterator("column-rows",function(b,c,e,d,f){return ia(b.aoData,f,"search"===a?"_aFilterData":"_aSortData",c)},1)});v("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,e,d){return ia(a.aoData,d,"anCells",b)},1)});v("columns().visible()","column().visible()",function(a,b){return this.iterator("column",function(c,e){if(a===k)return c.aoColumns[e].bVisible;var d=c.aoColumns,f=d[e],g=c.aoData,j,i,m;if(a!==k&&f.bVisible!==a){if(a){var l=
+h.inArray(!0,D(d,"bVisible"),e+1);j=0;for(i=g.length;j<i;j++)m=g[j].nTr,d=g[j].anCells,m&&m.insertBefore(d[e],d[l]||null)}else h(D(c.aoData,"anCells",e)).detach();f.bVisible=a;ea(c,c.aoHeader);ea(c,c.aoFooter);if(b===k||b)X(c),(c.oScroll.sX||c.oScroll.sY)&&Y(c);w(c,null,"column-visibility",[c,e,a]);ya(c)}})});v("columns().indexes()","column().index()",function(a){return this.iterator("column",function(b,c){return"visible"===a?$(b,c):c},1)});r("columns.adjust()",function(){return this.iterator("table",
+function(a){X(a)},1)});r("column.index()",function(a,b){if(0!==this.context.length){var c=this.context[0];if("fromVisible"===a||"toData"===a)return la(c,b);if("fromData"===a||"toVisible"===a)return $(c,b)}});r("column()",function(a,b){return bb(this.columns(a,b))});r("cells()",function(a,b,c){h.isPlainObject(a)&&(a.row===k?(c=a,a=null):(c=b,b=null));h.isPlainObject(b)&&(c=b,b=null);if(null===b||b===k)return this.iterator("table",function(b){var d=a,e=ab(c),f=b.aoData,g=Ca(b,e),i=Sb(ia(f,g,"anCells")),
+j=h([].concat.apply([],i)),l,m=b.aoColumns.length,o,r,t,s,u,v;return $a("cell",d,function(a){var c=typeof a==="function";if(a===null||a===k||c){o=[];r=0;for(t=g.length;r<t;r++){l=g[r];for(s=0;s<m;s++){u={row:l,column:s};if(c){v=b.aoData[l];a(u,x(b,l,s),v.anCells?v.anCells[s]:null)&&o.push(u)}else o.push(u)}}return o}return h.isPlainObject(a)?[a]:j.filter(a).map(function(a,b){l=b.parentNode._DT_RowIndex;return{row:l,column:h.inArray(b,f[l].anCells)}}).toArray()},b,e)});var e=this.columns(b,c),d=this.rows(a,
+c),f,g,j,i,m,l=this.iterator("table",function(a,b){f=[];g=0;for(j=d[b].length;g<j;g++){i=0;for(m=e[b].length;i<m;i++)f.push({row:d[b][g],column:e[b][i]})}return f},1);h.extend(l.selector,{cols:b,rows:a,opts:c});return l});v("cells().nodes()","cell().node()",function(){return this.iterator("cell",function(a,b,c){return(a=a.aoData[b].anCells)?a[c]:k},1)});r("cells().data()",function(){return this.iterator("cell",function(a,b,c){return x(a,b,c)},1)});v("cells().cache()","cell().cache()",function(a){a=
+"search"===a?"_aFilterData":"_aSortData";return this.iterator("cell",function(b,c,e){return b.aoData[c][a][e]},1)});v("cells().render()","cell().render()",function(a){return this.iterator("cell",function(b,c,e){return x(b,c,e,a)},1)});v("cells().indexes()","cell().index()",function(){return this.iterator("cell",function(a,b,c){return{row:b,column:c,columnVisible:$(a,c)}},1)});v("cells().invalidate()","cell().invalidate()",function(a){return this.iterator("cell",function(b,c,e){ca(b,c,a,e)})});r("cell()",
+function(a,b,c){return bb(this.cells(a,b,c))});r("cell().data()",function(a){var b=this.context,c=this[0];if(a===k)return b.length&&c.length?x(b[0],c[0].row,c[0].column):k;Ia(b[0],c[0].row,c[0].column,a);ca(b[0],c[0].row,"data",c[0].column);return this});r("order()",function(a,b){var c=this.context;if(a===k)return 0!==c.length?c[0].aaSorting:k;"number"===typeof a?a=[[a,b]]:h.isArray(a[0])||(a=Array.prototype.slice.call(arguments));return this.iterator("table",function(b){b.aaSorting=a.slice()})});
+r("order.listener()",function(a,b,c){return this.iterator("table",function(e){Oa(e,a,b,c)})});r(["columns().order()","column().order()"],function(a){var b=this;return this.iterator("table",function(c,e){var d=[];h.each(b[e],function(b,c){d.push([c,a])});c.aaSorting=d})});r("search()",function(a,b,c,e){var d=this.context;return a===k?0!==d.length?d[0].oPreviousSearch.sSearch:k:this.iterator("table",function(d){d.oFeatures.bFilter&&fa(d,h.extend({},d.oPreviousSearch,{sSearch:a+"",bRegex:null===b?!1:
+b,bSmart:null===c?!0:c,bCaseInsensitive:null===e?!0:e}),1)})});v("columns().search()","column().search()",function(a,b,c,e){return this.iterator("column",function(d,f){var g=d.aoPreSearchCols;if(a===k)return g[f].sSearch;d.oFeatures.bFilter&&(h.extend(g[f],{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===e?!0:e}),fa(d,d.oPreviousSearch,1))})});r("state()",function(){return this.context.length?this.context[0].oSavedState:null});r("state.clear()",function(){return this.iterator("table",
+function(a){a.fnStateSaveCallback.call(a.oInstance,a,{})})});r("state.loaded()",function(){return this.context.length?this.context[0].oLoadedState:null});r("state.save()",function(){return this.iterator("table",function(a){ya(a)})});m.versionCheck=m.fnVersionCheck=function(a){for(var b=m.version.split("."),a=a.split("."),c,e,d=0,f=a.length;d<f;d++)if(c=parseInt(b[d],10)||0,e=parseInt(a[d],10)||0,c!==e)return c>e;return!0};m.isDataTable=m.fnIsDataTable=function(a){var b=h(a).get(0),c=!1;h.each(m.settings,
+function(a,d){var f=d.nScrollHead?h("table",d.nScrollHead)[0]:null,g=d.nScrollFoot?h("table",d.nScrollFoot)[0]:null;if(d.nTable===b||f===b||g===b)c=!0});return c};m.tables=m.fnTables=function(a){return h.map(m.settings,function(b){if(!a||a&&h(b.nTable).is(":visible"))return b.nTable})};m.util={throttle:ua,escapeRegex:va};m.camelToHungarian=H;r("$()",function(a,b){var c=this.rows(b).nodes(),c=h(c);return h([].concat(c.filter(a).toArray(),c.find(a).toArray()))});h.each(["on","one","off"],function(a,
+b){r(b+"()",function(){var a=Array.prototype.slice.call(arguments);a[0].match(/\.dt\b/)||(a[0]+=".dt");var e=h(this.tables().nodes());e[b].apply(e,a);return this})});r("clear()",function(){return this.iterator("table",function(a){oa(a)})});r("settings()",function(){return new t(this.context,this.context)});r("init()",function(){var a=this.context;return a.length?a[0].oInit:null});r("data()",function(){return this.iterator("table",function(a){return D(a.aoData,"_aData")}).flatten()});r("destroy()",
+function(a){a=a||!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,e=b.oClasses,d=b.nTable,f=b.nTBody,g=b.nTHead,j=b.nTFoot,i=h(d),f=h(f),k=h(b.nTableWrapper),l=h.map(b.aoData,function(a){return a.nTr}),q;b.bDestroying=!0;w(b,"aoDestroyCallback","destroy",[b]);a||(new t(b)).columns().visible(!0);k.unbind(".DT").find(":not(tbody *)").unbind(".DT");h(Ea).unbind(".DT-"+b.sInstance);d!=g.parentNode&&(i.children("thead").detach(),i.append(g));j&&d!=j.parentNode&&(i.children("tfoot").detach(),
+i.append(j));i.detach();k.detach();b.aaSorting=[];b.aaSortingFixed=[];xa(b);h(l).removeClass(b.asStripeClasses.join(" "));h("th, td",g).removeClass(e.sSortable+" "+e.sSortableAsc+" "+e.sSortableDesc+" "+e.sSortableNone);b.bJUI&&(h("th span."+e.sSortIcon+", td span."+e.sSortIcon,g).detach(),h("th, td",g).each(function(){var a=h("div."+e.sSortJUIWrapper,this);h(this).append(a.contents());a.detach()}));!a&&c&&c.insertBefore(d,b.nTableReinsertBefore);f.children().detach();f.append(l);i.css("width",b.sDestroyWidth).removeClass(e.sTable);
+(q=b.asDestroyStripes.length)&&f.children().each(function(a){h(this).addClass(b.asDestroyStripes[a%q])});c=h.inArray(b,m.settings);-1!==c&&m.settings.splice(c,1)})});h.each(["column","row","cell"],function(a,b){r(b+"s().every()",function(a){return this.iterator(b,function(e,d,f){a.call((new t(e))[b](d,f))})})});r("i18n()",function(a,b,c){var e=this.context[0],a=R(a)(e.oLanguage);a===k&&(a=b);c!==k&&h.isPlainObject(a)&&(a=a[c]!==k?a[c]:a._);return a.replace("%d",c)});m.version="1.10.7";m.settings=
+[];m.models={};m.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};m.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null};m.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",
+sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};m.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bJQueryUI:!1,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,
+fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){}},fnStateLoadParams:null,
+fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+"_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},
+sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:h.extend({},m.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,
+sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null};W(m.defaults);m.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};W(m.defaults.column);m.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,
+bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],
+sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,
+bAjaxDataGet:!0,jqXHR:null,json:k,oAjaxData:k,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,bJUI:null,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==B(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==B(this)?1*this._iRecordsDisplay:
+this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,b=this._iDisplayStart,c=b+a,e=this.aiDisplay.length,d=this.oFeatures,f=d.bPaginate;return d.bServerSide?!1===f||-1===a?b+e:Math.min(b+a,this._iRecordsDisplay):!f||c>e||-1===a?e:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{}};m.ext=u={buttons:{},classes:{},errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},
+header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:m.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:m.version};h.extend(u,{afnFiltering:u.search,aTypes:u.type.detect,ofnSearch:u.type.search,oSort:u.type.order,afnSortData:u.order,aoFeatures:u.feature,oApi:u.internal,oStdClasses:u.classes,oPagination:u.pager});h.extend(m.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",
+sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",
+sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var Da="",Da="",F=Da+"ui-state-default",ja=Da+"css_right ui-icon ui-icon-",Xb=Da+"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix";h.extend(m.ext.oJUIClasses,
+m.ext.classes,{sPageButton:"fg-button ui-button "+F,sPageButtonActive:"ui-state-disabled",sPageButtonDisabled:"ui-state-disabled",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sSortAsc:F+" sorting_asc",sSortDesc:F+" sorting_desc",sSortable:F+" sorting",sSortableAsc:F+" sorting_asc_disabled",sSortableDesc:F+" sorting_desc_disabled",sSortableNone:F+" sorting_disabled",sSortJUIAsc:ja+"triangle-1-n",sSortJUIDesc:ja+"triangle-1-s",sSortJUI:ja+"carat-2-n-s",
+sSortJUIAscAllowed:ja+"carat-1-n",sSortJUIDescAllowed:ja+"carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sSortIcon:"DataTables_sort_icon",sScrollHead:"dataTables_scrollHead "+F,sScrollFoot:"dataTables_scrollFoot "+F,sHeaderTH:F,sFooterTH:F,sJUIHeader:Xb+" ui-corner-tl ui-corner-tr",sJUIFooter:Xb+" ui-corner-bl ui-corner-br"});var Mb=m.ext.pager;h.extend(Mb,{simple:function(){return["previous","next"]},full:function(){return["first","previous","next","last"]},simple_numbers:function(a,b){return["previous",
+Wa(a,b),"next"]},full_numbers:function(a,b){return["first","previous",Wa(a,b),"next","last"]},_numbers:Wa,numbers_length:7});h.extend(!0,m.ext.renderer,{pageButton:{_:function(a,b,c,e,d,f){var g=a.oClasses,j=a.oLanguage.oPaginate,i,k,l=0,m=function(b,e){var n,r,t,s,u=function(b){Ta(a,b.data.action,true)};n=0;for(r=e.length;n<r;n++){s=e[n];if(h.isArray(s)){t=h("<"+(s.DT_el||"div")+"/>").appendTo(b);m(t,s)}else{k=i="";switch(s){case "ellipsis":b.append('<span class="ellipsis">&#x2026;</span>');break;
+case "first":i=j.sFirst;k=s+(d>0?"":" "+g.sPageButtonDisabled);break;case "previous":i=j.sPrevious;k=s+(d>0?"":" "+g.sPageButtonDisabled);break;case "next":i=j.sNext;k=s+(d<f-1?"":" "+g.sPageButtonDisabled);break;case "last":i=j.sLast;k=s+(d<f-1?"":" "+g.sPageButtonDisabled);break;default:i=s+1;k=d===s?g.sPageButtonActive:""}if(i){t=h("<a>",{"class":g.sPageButton+" "+k,"aria-controls":a.sTableId,"data-dt-idx":l,tabindex:a.iTabIndex,id:c===0&&typeof s==="string"?a.sTableId+"_"+s:null}).html(i).appendTo(b);
+Va(t,{action:s},u);l++}}}},n;try{n=h(Q.activeElement).data("dt-idx")}catch(r){}m(h(b).empty(),e);n&&h(b).find("[data-dt-idx="+n+"]").focus()}}});h.extend(m.ext.type.detect,[function(a,b){var c=b.oLanguage.sDecimal;return Za(a,c)?"num"+c:null},function(a){if(a&&!(a instanceof Date)&&(!ac.test(a)||!bc.test(a)))return null;var b=Date.parse(a);return null!==b&&!isNaN(b)||J(a)?"date":null},function(a,b){var c=b.oLanguage.sDecimal;return Za(a,c,!0)?"num-fmt"+c:null},function(a,b){var c=b.oLanguage.sDecimal;
+return Rb(a,c)?"html-num"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Rb(a,c,!0)?"html-num-fmt"+c:null},function(a){return J(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);h.extend(m.ext.type.search,{html:function(a){return J(a)?a:"string"===typeof a?a.replace(Ob," ").replace(Ba,""):""},string:function(a){return J(a)?a:"string"===typeof a?a.replace(Ob," "):a}});var Aa=function(a,b,c,e){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=Qb(a,b));a.replace&&(c&&(a=a.replace(c,"")),
+e&&(a=a.replace(e,"")));return 1*a};h.extend(u.type.order,{"date-pre":function(a){return Date.parse(a)||0},"html-pre":function(a){return J(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return J(a)?"":"string"===typeof a?a.toLowerCase():!a.toString?"":a.toString()},"string-asc":function(a,b){return a<b?-1:a>b?1:0},"string-desc":function(a,b){return a<b?1:a>b?-1:0}});db("");h.extend(!0,m.ext.renderer,{header:{_:function(a,b,c,e){h(a.nTable).on("order.dt.DT",function(d,
+f,g,h){if(a===f){d=c.idx;b.removeClass(c.sSortingClass+" "+e.sSortAsc+" "+e.sSortDesc).addClass(h[d]=="asc"?e.sSortAsc:h[d]=="desc"?e.sSortDesc:c.sSortingClass)}})},jqueryui:function(a,b,c,e){h("<div/>").addClass(e.sSortJUIWrapper).append(b.contents()).append(h("<span/>").addClass(e.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b);h(a.nTable).on("order.dt.DT",function(d,f,g,h){if(a===f){d=c.idx;b.removeClass(e.sSortAsc+" "+e.sSortDesc).addClass(h[d]=="asc"?e.sSortAsc:h[d]=="desc"?e.sSortDesc:c.sSortingClass);
+b.find("span."+e.sSortIcon).removeClass(e.sSortJUIAsc+" "+e.sSortJUIDesc+" "+e.sSortJUI+" "+e.sSortJUIAscAllowed+" "+e.sSortJUIDescAllowed).addClass(h[d]=="asc"?e.sSortJUIAsc:h[d]=="desc"?e.sSortJUIDesc:c.sSortingClassJUI)}})}}});m.render={number:function(a,b,c,e){return{display:function(d){if("number"!==typeof d&&"string"!==typeof d)return d;var f=0>d?"-":"",d=Math.abs(parseFloat(d)),g=parseInt(d,10),d=c?b+(d-g).toFixed(c).substring(2):"";return f+(e||"")+g.toString().replace(/\B(?=(\d{3})+(?!\d))/g,
+a)+d}}}};h.extend(m.ext.internal,{_fnExternApiFunc:Nb,_fnBuildAjax:ra,_fnAjaxUpdate:kb,_fnAjaxParameters:tb,_fnAjaxUpdateDraw:ub,_fnAjaxDataSrc:sa,_fnAddColumn:Fa,_fnColumnOptions:ka,_fnAdjustColumnSizing:X,_fnVisibleToColumnIndex:la,_fnColumnIndexToVisible:$,_fnVisbleColumns:aa,_fnGetColumns:Z,_fnColumnTypes:Ha,_fnApplyColumnDefs:ib,_fnHungarianMap:W,_fnCamelToHungarian:H,_fnLanguageCompat:P,_fnBrowserDetect:gb,_fnAddData:K,_fnAddTr:ma,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==k?b._DT_RowIndex:
+null},_fnNodeToColumnIndex:function(a,b,c){return h.inArray(c,a.aoData[b].anCells)},_fnGetCellData:x,_fnSetCellData:Ia,_fnSplitObjNotation:Ka,_fnGetObjectDataFn:R,_fnSetObjectDataFn:S,_fnGetDataMaster:La,_fnClearTable:oa,_fnDeleteIndex:pa,_fnInvalidate:ca,_fnGetRowElements:na,_fnCreateTr:Ja,_fnBuildHead:jb,_fnDrawHead:ea,_fnDraw:M,_fnReDraw:N,_fnAddOptionsHtml:mb,_fnDetectHeader:da,_fnGetUniqueThs:qa,_fnFeatureHtmlFilter:ob,_fnFilterComplete:fa,_fnFilterCustom:xb,_fnFilterColumn:wb,_fnFilter:vb,_fnFilterCreateSearch:Qa,
+_fnEscapeRegex:va,_fnFilterData:yb,_fnFeatureHtmlInfo:rb,_fnUpdateInfo:Bb,_fnInfoMacros:Cb,_fnInitialise:ga,_fnInitComplete:ta,_fnLengthChange:Ra,_fnFeatureHtmlLength:nb,_fnFeatureHtmlPaginate:sb,_fnPageChange:Ta,_fnFeatureHtmlProcessing:pb,_fnProcessingDisplay:C,_fnFeatureHtmlTable:qb,_fnScrollDraw:Y,_fnApplyToChildren:G,_fnCalculateColumnWidths:Ga,_fnThrottle:ua,_fnConvertToWidth:Db,_fnScrollingWidthAdjust:Fb,_fnGetWidestNode:Eb,_fnGetMaxLenString:Gb,_fnStringToCss:s,_fnScrollBarWidth:Hb,_fnSortFlatten:U,
+_fnSort:lb,_fnSortAria:Jb,_fnSortListener:Ua,_fnSortAttachListener:Oa,_fnSortingClasses:xa,_fnSortData:Ib,_fnSaveState:ya,_fnLoadState:Kb,_fnSettingsFromNode:za,_fnLog:I,_fnMap:E,_fnBindAction:Va,_fnCallbackReg:z,_fnCallbackFire:w,_fnLengthOverflow:Sa,_fnRenderer:Pa,_fnDataSource:B,_fnRowAttributes:Ma,_fnCalculateEnd:function(){}});h.fn.dataTable=m;h.fn.dataTableSettings=m.settings;h.fn.dataTableExt=m.ext;h.fn.DataTable=function(a){return h(this).dataTable(a).api()};h.each(m,function(a,b){h.fn.DataTable[a]=
+b});return h.fn.dataTable};"function"===typeof define&&define.amd?define("datatables",["jquery"],P):"object"===typeof exports?module.exports=P(require("jquery")):jQuery&&!jQuery.fn.dataTable&&P(jQuery)})(window,document);
diff --git a/htdocs/Libs/DataTables-1.10.3/media/js/jquery.js b/htdocs/Libs/DataTables-1.10.3/media/js/jquery.js
new file mode 100644
index 0000000..fdd413a
--- /dev/null
+++ b/htdocs/Libs/DataTables-1.10.3/media/js/jquery.js
@@ -0,0 +1,5 @@
+/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.3",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b="length"in a&&a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\f]' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function qa(){}qa.prototype=d.filters=d.pseudos,d.setFilters=new qa,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function ra(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;
+
+return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function aa(){return!0}function ba(){return!1}function ca(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[m.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=Z.test(e)?this.mouseHooks:Y.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new m.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||y),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},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(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||y,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==ca()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===ca()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return m.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return m.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=m.extend(new m.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?m.event.trigger(e,null,b):m.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},m.removeEvent=y.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===K&&(a[d]=null),a.detachEvent(d,c))},m.Event=function(a,b){return this instanceof m.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?aa:ba):this.type=a,b&&m.extend(this,b),this.timeStamp=a&&a.timeStamp||m.now(),void(this[m.expando]=!0)):new m.Event(a,b)},m.Event.prototype={isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=aa,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=aa,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=aa,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},m.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){m.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!m.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.submitBubbles||(m.event.special.submit={setup:function(){return m.nodeName(this,"form")?!1:void m.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=m.nodeName(b,"input")||m.nodeName(b,"button")?b.form:void 0;c&&!m._data(c,"submitBubbles")&&(m.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),m._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&m.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return m.nodeName(this,"form")?!1:void m.event.remove(this,"._submit")}}),k.changeBubbles||(m.event.special.change={setup:function(){return X.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(m.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),m.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),m.event.simulate("change",this,a,!0)})),!1):void m.event.add(this,"beforeactivate._change",function(a){var b=a.target;X.test(b.nodeName)&&!m._data(b,"changeBubbles")&&(m.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||m.event.simulate("change",this.parentNode,a,!0)}),m._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return m.event.remove(this,"._change"),!X.test(this.nodeName)}}),k.focusinBubbles||m.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){m.event.simulate(b,a.target,m.event.fix(a),!0)};m.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=m._data(d,b);e||d.addEventListener(a,c,!0),m._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=m._data(d,b)-1;e?m._data(d,b,e):(d.removeEventListener(a,c,!0),m._removeData(d,b))}}}),m.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=ba;else if(!d)return this;return 1===e&&(g=d,d=function(a){return m().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=m.guid++)),this.each(function(){m.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,m(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=ba),this.each(function(){m.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){m.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?m.event.trigger(a,b,c,!0):void 0}});function da(a){var b=ea.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var ea="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",fa=/ jQuery\d+="(?:null|\d+)"/g,ga=new RegExp("<(?:"+ea+")[\\s/>]","i"),ha=/^\s+/,ia=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ja=/<([\w:]+)/,ka=/<tbody/i,la=/<|&#?\w+;/,ma=/<(?:script|style|link)/i,na=/checked\s*(?:[^=]|=\s*.checked.)/i,oa=/^$|\/(?:java|ecma)script/i,pa=/^true\/(.*)/,qa=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ra={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:k.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},sa=da(y),ta=sa.appendChild(y.createElement("div"));ra.optgroup=ra.option,ra.tbody=ra.tfoot=ra.colgroup=ra.caption=ra.thead,ra.th=ra.td;function ua(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ua(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function va(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wa(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xa(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function ya(a){var b=pa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function za(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Aa(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Ba(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xa(b).text=a.text,ya(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!ga.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ta.innerHTML=a.outerHTML,ta.removeChild(f=ta.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ua(f),h=ua(a),g=0;null!=(e=h[g]);++g)d[g]&&Ba(e,d[g]);if(b)if(c)for(h=h||ua(a),d=d||ua(f),g=0;null!=(e=h[g]);g++)Aa(e,d[g]);else Aa(a,f);return d=ua(f,"script"),d.length>0&&za(d,!i&&ua(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=da(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(la.test(f)){h=h||o.appendChild(b.createElement("div")),i=(ja.exec(f)||["",""])[1].toLowerCase(),l=ra[i]||ra._default,h.innerHTML=l[1]+f.replace(ia,"<$1></$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&ha.test(f)&&p.push(b.createTextNode(ha.exec(f)[0])),!k.tbody){f="table"!==i||ka.test(f)?"<table>"!==l[1]||ka.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ua(p,"input"),va),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ua(o.appendChild(f),"script"),g&&za(h),c)){e=0;while(f=h[e++])oa.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ua(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&za(ua(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ua(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fa,""):void 0;if(!("string"!=typeof a||ma.test(a)||!k.htmlSerialize&&ga.test(a)||!k.leadingWhitespace&&ha.test(a)||ra[(ja.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ia,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ua(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ua(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&na.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ua(i,"script"),xa),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ua(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,ya),j=0;f>j;j++)d=g[j],oa.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qa,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Ca,Da={};function Ea(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fa(a){var b=y,c=Da[a];return c||(c=Ea(a,b),"none"!==c&&c||(Ca=(Ca||m("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Ca[0].contentWindow||Ca[0].contentDocument).document,b.write(),b.close(),c=Ea(a,b),Ca.detach()),Da[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Ga=/^margin/,Ha=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ia,Ja,Ka=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ia=function(b){return b.ownerDocument.defaultView.opener?b.ownerDocument.defaultView.getComputedStyle(b,null):a.getComputedStyle(b,null)},Ja=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ia(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Ha.test(g)&&Ga.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ia=function(a){return a.currentStyle},Ja=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ia(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Ha.test(g)&&!Ka.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function La(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight),b.removeChild(i)),b.innerHTML="<table><tr><td></td><td>t</td></tr></table>",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Ma=/alpha\([^)]*\)/i,Na=/opacity\s*=\s*([^)]*)/,Oa=/^(none|table(?!-c[ea]).+)/,Pa=new RegExp("^("+S+")(.*)$","i"),Qa=new RegExp("^([+-])=("+S+")","i"),Ra={position:"absolute",visibility:"hidden",display:"block"},Sa={letterSpacing:"0",fontWeight:"400"},Ta=["Webkit","O","Moz","ms"];function Ua(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Ta.length;while(e--)if(b=Ta[e]+c,b in a)return b;return d}function Va(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fa(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wa(a,b,c){var d=Pa.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xa(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Ya(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ia(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Ja(a,b,f),(0>e||null==e)&&(e=a.style[b]),Ha.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xa(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Ja(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ua(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qa.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ua(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Ja(a,b,d)),"normal"===f&&b in Sa&&(f=Sa[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Oa.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Ra,function(){return Ya(a,b,d)}):Ya(a,b,d):void 0},set:function(a,c,d){var e=d&&Ia(a);return Wa(a,c,d?Xa(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Na.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Ma,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Ma.test(f)?f.replace(Ma,e):f+" "+e)}}),m.cssHooks.marginRight=La(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Ja,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Ga.test(a)||(m.cssHooks[a+b].set=Wa)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ia(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Va(this,!0)},hide:function(){return Va(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Za(a,b,c,d,e){
+return new Za.prototype.init(a,b,c,d,e)}m.Tween=Za,Za.prototype={constructor:Za,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")},cur:function(){var a=Za.propHooks[this.prop];return a&&a.get?a.get(this):Za.propHooks._default.get(this)},run:function(a){var b,c=Za.propHooks[this.prop];return this.options.duration?this.pos=b=m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Za.propHooks._default.set(this),this}},Za.prototype.init.prototype=Za.prototype,Za.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Za.propHooks.scrollTop=Za.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Za.prototype.init,m.fx.step={};var $a,_a,ab=/^(?:toggle|show|hide)$/,bb=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cb=/queueHooks$/,db=[ib],eb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bb.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bb.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fb(){return setTimeout(function(){$a=void 0}),$a=m.now()}function gb(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hb(a,b,c){for(var d,e=(eb[b]||[]).concat(eb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fa(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fa(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ab.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fa(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hb(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=db.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$a||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$a||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);g>f;f++)if(d=db[f].call(j,a,k,j.opts))return d;return m.map(k,hb,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kb,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],eb[c]=eb[c]||[],eb[c].unshift(b)},prefilter:function(a,b){b?db.unshift(a):db.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kb(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gb(b,!0),a,d,e)}}),m.each({slideDown:gb("show"),slideUp:gb("hide"),slideToggle:gb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($a=m.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||m.fx.stop(),$a=void 0},m.fx.timer=function(a){m.timers.push(a),a()?m.fx.start():m.timers.pop()},m.fx.interval=13,m.fx.start=function(){_a||(_a=setInterval(m.fx.tick,m.fx.interval))},m.fx.stop=function(){clearInterval(_a),_a=null},m.fx.speeds={slow:600,fast:200,_default:400},m.fn.delay=function(a,b){return a=m.fx?m.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e;b=y.createElement("div"),b.setAttribute("className","t"),b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lb=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lb,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mb,nb,ob=m.expr.attrHandle,pb=/^(?:checked|selected)$/i,qb=k.getSetAttribute,rb=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nb:mb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rb&&qb||!pb.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qb?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nb={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rb&&qb||!pb.test(c)?a.setAttribute(!qb&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=ob[b]||m.find.attr;ob[b]=rb&&qb||!pb.test(b)?function(a,b,d){var e,f;return d||(f=ob[b],ob[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,ob[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rb&&qb||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mb&&mb.set(a,b,c)}}),qb||(mb={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},ob.id=ob.name=ob.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mb.set},m.attrHooks.contenteditable={set:function(a,b,c){mb.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sb=/^(?:input|select|textarea|button|object)$/i,tb=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sb.test(a.nodeName)||tb.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var ub=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ub," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ub," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ub," ").indexOf(b)>=0)return!0;return!1}}),m.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(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vb=m.now(),wb=/\?/,xb=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xb,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yb,zb,Ab=/#.*$/,Bb=/([?&])_=[^&]*/,Cb=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Db=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Eb=/^(?:GET|HEAD)$/,Fb=/^\/\//,Gb=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hb={},Ib={},Jb="*/".concat("*");try{zb=location.href}catch(Kb){zb=y.createElement("a"),zb.href="",zb=zb.href}yb=Gb.exec(zb.toLowerCase())||[];function Lb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mb(a,b,c,d){var e={},f=a===Ib;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nb(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Ob(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zb,type:"GET",isLocal:Db.test(yb[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jb,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":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nb(Nb(a,m.ajaxSettings),b):Nb(m.ajaxSettings,a)},ajaxPrefilter:Lb(Hb),ajaxTransport:Lb(Ib),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cb.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zb)+"").replace(Ab,"").replace(Fb,yb[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gb.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yb[1]&&c[2]===yb[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yb[3]||("http:"===yb[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mb(Hb,k,b,v),2===t)return v;h=m.event&&k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Eb.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wb.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bb.test(e)?e.replace(Bb,"$1_="+vb++):e+(wb.test(e)?"&":"?")+"_="+vb++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jb+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mb(Ib,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Ob(k,v,c)),u=Pb(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qb=/%20/g,Rb=/\[\]$/,Sb=/\r?\n/g,Tb=/^(?:submit|button|image|reset|file)$/i,Ub=/^(?:input|select|textarea|keygen)/i;function Vb(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rb.test(a)?d(a,e):Vb(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vb(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vb(c,a[c],b,e);return d.join("&").replace(Qb,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Ub.test(this.nodeName)&&!Tb.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sb,"\r\n")}}):{name:b.name,value:c.replace(Sb,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zb()||$b()}:Zb;var Wb=0,Xb={},Yb=m.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in Xb)Xb[a](void 0,!0)}),k.cors=!!Yb&&"withCredentials"in Yb,Yb=k.ajax=!!Yb,Yb&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wb;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xb[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xb[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zb(){try{return new a.XMLHttpRequest}catch(b){}}function $b(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _b=[],ac=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_b.pop()||m.expando+"_"+vb++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ac.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ac.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ac,"$1"+e):b.jsonp!==!1&&(b.url+=(wb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_b.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bc=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bc)return bc.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("<div>").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cc=a.document.documentElement;function dc(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dc(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cc;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cc})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dc(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=La(k.pixelPosition,function(a,c){return c?(c=Ja(a,b),Ha.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ec=a.jQuery,fc=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fc),b&&a.jQuery===m&&(a.jQuery=ec),m},typeof b===K&&(a.jQuery=a.$=m),m});
\ No newline at end of file
diff --git a/htdocs/Libs/Flot/excanvas.min.js b/htdocs/Libs/Flot/excanvas.min.js
new file mode 100644
index 0000000..fcf876c
--- /dev/null
+++ b/htdocs/Libs/Flot/excanvas.min.js
@@ -0,0 +1 @@
+if(!document.createElement("canvas").getContext){(function(){var ab=Math;var n=ab.round;var l=ab.sin;var A=ab.cos;var H=ab.abs;var N=ab.sqrt;var d=10;var f=d/2;var z=+navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];function y(){return this.context_||(this.context_=new D(this))}var t=Array.prototype.slice;function g(j,m,p){var i=t.call(arguments,2);return function(){return j.apply(m,i.concat(t.call(arguments)))}}function af(i){return String(i).replace(/&/g,"&amp;").replace(/"/g,"&quot;")}function Y(m,j,i){if(!m.namespaces[j]){m.namespaces.add(j,i,"#default#VML")}}function R(j){Y(j,"g_vml_","urn:schemas-microsoft-com:vml");Y(j,"g_o_","urn:schemas-microsoft-com:office:office");if(!j.styleSheets.ex_canvas_){var i=j.createStyleSheet();i.owningElement.id="ex_canvas_";i.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}"}}R(document);var e={init:function(i){var j=i||document;j.createElement("canvas");j.attachEvent("onreadystatechange",g(this.init_,this,j))},init_:function(p){var m=p.getElementsByTagName("canvas");for(var j=0;j<m.length;j++){this.initElement(m[j])}},initElement:function(j){if(!j.getContext){j.getContext=y;R(j.ownerDocument);j.innerHTML="";j.attachEvent("onpropertychange",x);j.attachEvent("onresize",W);var i=j.attributes;if(i.width&&i.width.specified){j.style.width=i.width.nodeValue+"px"}else{j.width=j.clientWidth}if(i.height&&i.height.specified){j.style.height=i.height.nodeValue+"px"}else{j.height=j.clientHeight}}return j}};function x(j){var i=j.srcElement;switch(j.propertyName){case"width":i.getContext().clearRect();i.style.width=i.attributes.width.nodeValue+"px";i.firstChild.style.width=i.clientWidth+"px";break;case"height":i.getContext().clearRect();i.style.height=i.attributes.height.nodeValue+"px";i.firstChild.style.height=i.clientHeight+"px";break}}function W(j){var i=j.srcElement;if(i.firstChild){i.firstChild.style.width=i.clientWidth+"px";i.firstChild.style.height=i.clientHeight+"px"}}e.init();var k=[];for(var ae=0;ae<16;ae++){for(var ad=0;ad<16;ad++){k[ae*16+ad]=ae.toString(16)+ad.toString(16)}}function B(){return[[1,0,0],[0,1,0],[0,0,1]]}function J(p,m){var j=B();for(var i=0;i<3;i++){for(var ah=0;ah<3;ah++){var Z=0;for(var ag=0;ag<3;ag++){Z+=p[i][ag]*m[ag][ah]}j[i][ah]=Z}}return j}function v(j,i){i.fillStyle=j.fillStyle;i.lineCap=j.lineCap;i.lineJoin=j.lineJoin;i.lineWidth=j.lineWidth;i.miterLimit=j.miterLimit;i.shadowBlur=j.shadowBlur;i.shadowColor=j.shadowColor;i.shadowOffsetX=j.shadowOffsetX;i.shadowOffsetY=j.shadowOffsetY;i.strokeStyle=j.strokeStyle;i.globalAlpha=j.globalAlpha;i.font=j.font;i.textAlign=j.textAlign;i.textBaseline=j.textBaseline;i.arcScaleX_=j.arcScaleX_;i.arcScaleY_=j.arcScaleY_;i.lineScale_=j.lineScale_}var b={aliceblue:"#F0F8FF",antiquewhite:"#FAEBD7",aquamarine:"#7FFFD4",azure:"#F0FFFF",beige:"#F5F5DC",bisque:"#FFE4C4",black:"#000000",blanchedalmond:"#FFEBCD",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",darkgreen:"#006400",darkgrey:"#A9A9A9",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",gainsboro:"#DCDCDC",ghostwhite:"#F8F8FF",gold:"#FFD700",goldenrod:"#DAA520",grey:"#808080",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",lightgreen:"#90EE90",lightgrey:"#D3D3D3",lightpink:"#FFB6C1",lightsalmon:"#FFA07A",lightseagreen:"#20B2AA",lightskyblue:"#87CEFA",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#B0C4DE",lightyellow:"#FFFFE0",limegreen:"#32CD32",linen:"#FAF0E6",magenta:"#FF00FF",mediumaquamarine:"#66CDAA",mediumblue:"#0000CD",mediumorchid:"#BA55D3",mediumpurple:"#9370DB",mediumseagreen:"#3CB371",mediumslateblue:"#7B68EE",mediumspringgreen:"#00FA9A",mediumturquoise:"#48D1CC",mediumvioletred:"#C71585",midnightblue:"#191970",mintcream:"#F5FFFA",mistyrose:"#FFE4E1",moccasin:"#FFE4B5",navajowhite:"#FFDEAD",oldlace:"#FDF5E6",olivedrab:"#6B8E23",orange:"#FFA500",orangered:"#FF4500",orchid:"#DA70D6",palegoldenrod:"#EEE8AA",palegreen:"#98FB98",paleturquoise:"#AFEEEE",palevioletred:"#DB7093",papayawhip:"#FFEFD5",peachpuff:"#FFDAB9",peru:"#CD853F",pink:"#FFC0CB",plum:"#DDA0DD",powderblue:"#B0E0E6",rosybrown:"#BC8F8F",royalblue:"#4169E1",saddlebrown:"#8B4513",salmon:"#FA8072",sandybrown:"#F4A460",seagreen:"#2E8B57",seashell:"#FFF5EE",sienna:"#A0522D",skyblue:"#87CEEB",slateblue:"#6A5ACD",slategray:"#708090",slategrey:"#708090",snow:"#FFFAFA",springgreen:"#00FF7F",steelblue:"#4682B4",tan:"#D2B48C",thistle:"#D8BFD8",tomato:"#FF6347",turquoise:"#40E0D0",violet:"#EE82EE",wheat:"#F5DEB3",whitesmoke:"#F5F5F5",yellowgreen:"#9ACD32"};function M(j){var p=j.indexOf("(",3);var i=j.indexOf(")",p+1);var m=j.substring(p+1,i).split(",");if(m.length!=4||j.charAt(3)!="a"){m[3]=1}return m}function c(i){return parseFloat(i)/100}function r(j,m,i){return Math.min(i,Math.max(m,j))}function I(ag){var i,ai,aj,ah,ak,Z;ah=parseFloat(ag[0])/360%360;if(ah<0){ah++}ak=r(c(ag[1]),0,1);Z=r(c(ag[2]),0,1);if(ak==0){i=ai=aj=Z}else{var j=Z<0.5?Z*(1+ak):Z+ak-Z*ak;var m=2*Z-j;i=a(m,j,ah+1/3);ai=a(m,j,ah);aj=a(m,j,ah-1/3)}return"#"+k[Math.floor(i*255)]+k[Math.floor(ai*255)]+k[Math.floor(aj*255)]}function a(j,i,m){if(m<0){m++}if(m>1){m--}if(6*m<1){return j+(i-j)*6*m}else{if(2*m<1){return i}else{if(3*m<2){return j+(i-j)*(2/3-m)*6}else{return j}}}}var C={};function F(j){if(j in C){return C[j]}var ag,Z=1;j=String(j);if(j.charAt(0)=="#"){ag=j}else{if(/^rgb/.test(j)){var p=M(j);var ag="#",ah;for(var m=0;m<3;m++){if(p[m].indexOf("%")!=-1){ah=Math.floor(c(p[m])*255)}else{ah=+p[m]}ag+=k[r(ah,0,255)]}Z=+p[3]}else{if(/^hsl/.test(j)){var p=M(j);ag=I(p);Z=p[3]}else{ag=b[j]||j}}}return C[j]={color:ag,alpha:Z}}var o={style:"normal",variant:"normal",weight:"normal",size:10,family:"sans-serif"};var L={};function E(i){if(L[i]){return L[i]}var p=document.createElement("div");var m=p.style;try{m.font=i}catch(j){}return L[i]={style:m.fontStyle||o.style,variant:m.fontVariant||o.variant,weight:m.fontWeight||o.weight,size:m.fontSize||o.size,family:m.fontFamily||o.family}}function u(m,j){var i={};for(var ah in m){i[ah]=m[ah]}var ag=parseFloat(j.currentStyle.fontSize),Z=parseFloat(m.size);if(typeof m.size=="number"){i.size=m.size}else{if(m.size.indexOf("px")!=-1){i.size=Z}else{if(m.size.indexOf("em")!=-1){i.size=ag*Z}else{if(m.size.indexOf("%")!=-1){i.size=(ag/100)*Z}else{if(m.size.indexOf("pt")!=-1){i.size=Z/0.75}else{i.size=ag}}}}}i.size*=0.981;return i}function ac(i){return i.style+" "+i.variant+" "+i.weight+" "+i.size+"px "+i.family}var s={butt:"flat",round:"round"};function S(i){return s[i]||"square"}function D(i){this.m_=B();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle="#000";this.fillStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=d*1;this.globalAlpha=1;this.font="10px sans-serif";this.textAlign="left";this.textBaseline="alphabetic";this.canvas=i;var m="width:"+i.clientWidth+"px;height:"+i.clientHeight+"px;overflow:hidden;position:absolute";var j=i.ownerDocument.createElement("div");j.style.cssText=m;i.appendChild(j);var p=j.cloneNode(false);p.style.backgroundColor="red";p.style.filter="alpha(opacity=0)";i.appendChild(p);this.element_=j;this.arcScaleX_=1;this.arcScaleY_=1;this.lineScale_=1}var q=D.prototype;q.clearRect=function(){if(this.textMeasureEl_){this.textMeasureEl_.removeNode(true);this.textMeasureEl_=null}this.element_.innerHTML=""};q.beginPath=function(){this.currentPath_=[]};q.moveTo=function(j,i){var m=V(this,j,i);this.currentPath_.push({type:"moveTo",x:m.x,y:m.y});this.currentX_=m.x;this.currentY_=m.y};q.lineTo=function(j,i){var m=V(this,j,i);this.currentPath_.push({type:"lineTo",x:m.x,y:m.y});this.currentX_=m.x;this.currentY_=m.y};q.bezierCurveTo=function(m,j,ak,aj,ai,ag){var i=V(this,ai,ag);var ah=V(this,m,j);var Z=V(this,ak,aj);K(this,ah,Z,i)};function K(i,Z,m,j){i.currentPath_.push({type:"bezierCurveTo",cp1x:Z.x,cp1y:Z.y,cp2x:m.x,cp2y:m.y,x:j.x,y:j.y});i.currentX_=j.x;i.currentY_=j.y}q.quadraticCurveTo=function(ai,m,j,i){var ah=V(this,ai,m);var ag=V(this,j,i);var aj={x:this.currentX_+2/3*(ah.x-this.currentX_),y:this.currentY_+2/3*(ah.y-this.currentY_)};var Z={x:aj.x+(ag.x-this.currentX_)/3,y:aj.y+(ag.y-this.currentY_)/3};K(this,aj,Z,ag)};q.arc=function(al,aj,ak,ag,j,m){ak*=d;var ap=m?"at":"wa";var am=al+A(ag)*ak-f;var ao=aj+l(ag)*ak-f;var i=al+A(j)*ak-f;var an=aj+l(j)*ak-f;if(am==i&&!m){am+=0.125}var Z=V(this,al,aj);var ai=V(this,am,ao);var ah=V(this,i,an);this.currentPath_.push({type:ap,x:Z.x,y:Z.y,radius:ak,xStart:ai.x,yStart:ai.y,xEnd:ah.x,yEnd:ah.y})};q.rect=function(m,j,i,p){this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath()};q.strokeRect=function(m,j,i,p){var Z=this.currentPath_;this.beginPath();this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath();this.stroke();this.currentPath_=Z};q.fillRect=function(m,j,i,p){var Z=this.currentPath_;this.beginPath();this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath();this.fill();this.currentPath_=Z};q.createLinearGradient=function(j,p,i,m){var Z=new U("gradient");Z.x0_=j;Z.y0_=p;Z.x1_=i;Z.y1_=m;return Z};q.createRadialGradient=function(p,ag,m,j,Z,i){var ah=new U("gradientradial");ah.x0_=p;ah.y0_=ag;ah.r0_=m;ah.x1_=j;ah.y1_=Z;ah.r1_=i;return ah};q.drawImage=function(aq,m){var aj,ah,al,ay,ao,am,at,aA;var ak=aq.runtimeStyle.width;var ap=aq.runtimeStyle.height;aq.runtimeStyle.width="auto";aq.runtimeStyle.height="auto";var ai=aq.width;var aw=aq.height;aq.runtimeStyle.width=ak;aq.runtimeStyle.height=ap;if(arguments.length==3){aj=arguments[1];ah=arguments[2];ao=am=0;at=al=ai;aA=ay=aw}else{if(arguments.length==5){aj=arguments[1];ah=arguments[2];al=arguments[3];ay=arguments[4];ao=am=0;at=ai;aA=aw}else{if(arguments.length==9){ao=arguments[1];am=arguments[2];at=arguments[3];aA=arguments[4];aj=arguments[5];ah=arguments[6];al=arguments[7];ay=arguments[8]}else{throw Error("Invalid number of arguments")}}}var az=V(this,aj,ah);var p=at/2;var j=aA/2;var ax=[];var i=10;var ag=10;ax.push(" <g_vml_:group",' coordsize="',d*i,",",d*ag,'"',' coordorigin="0,0"',' style="width:',i,"px;height:",ag,"px;position:absolute;");if(this.m_[0][0]!=1||this.m_[0][1]||this.m_[1][1]!=1||this.m_[1][0]){var Z=[];Z.push("M11=",this.m_[0][0],",","M12=",this.m_[1][0],",","M21=",this.m_[0][1],",","M22=",this.m_[1][1],",","Dx=",n(az.x/d),",","Dy=",n(az.y/d),"");var av=az;var au=V(this,aj+al,ah);var ar=V(this,aj,ah+ay);var an=V(this,aj+al,ah+ay);av.x=ab.max(av.x,au.x,ar.x,an.x);av.y=ab.max(av.y,au.y,ar.y,an.y);ax.push("padding:0 ",n(av.x/d),"px ",n(av.y/d),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",Z.join(""),", sizingmethod='clip');")}else{ax.push("top:",n(az.y/d),"px;left:",n(az.x/d),"px;")}ax.push(' ">','<g_vml_:image src="',aq.src,'"',' style="width:',d*al,"px;"," height:",d*ay,'px"',' cropleft="',ao/ai,'"',' croptop="',am/aw,'"',' cropright="',(ai-ao-at)/ai,'"',' cropbottom="',(aw-am-aA)/aw,'"'," />","</g_vml_:group>");this.element_.insertAdjacentHTML("BeforeEnd",ax.join(""))};q.stroke=function(ao){var Z=10;var ap=10;var ag=5000;var ai={x:null,y:null};var an={x:null,y:null};for(var aj=0;aj<this.currentPath_.length;aj+=ag){var am=[];var ah=false;am.push("<g_vml_:shape",' filled="',!!ao,'"',' style="position:absolute;width:',Z,"px;height:",ap,'px;"',' coordorigin="0,0"',' coordsize="',d*Z,",",d*ap,'"',' stroked="',!ao,'"',' path="');var aq=false;for(var ak=aj;ak<Math.min(aj+ag,this.currentPath_.length);ak++){if(ak%ag==0&&ak>0){am.push(" m ",n(this.currentPath_[ak-1].x),",",n(this.currentPath_[ak-1].y))}var m=this.currentPath_[ak];var al;switch(m.type){case"moveTo":al=m;am.push(" m ",n(m.x),",",n(m.y));break;case"lineTo":am.push(" l ",n(m.x),",",n(m.y));break;case"close":am.push(" x ");m=null;break;case"bezierCurveTo":am.push(" c ",n(m.cp1x),",",n(m.cp1y),",",n(m.cp2x),",",n(m.cp2y),",",n(m.x),",",n(m.y));break;case"at":case"wa":am.push(" ",m.type," ",n(m.x-this.arcScaleX_*m.radius),",",n(m.y-this.arcScaleY_*m.radius)," ",n(m.x+this.arcScaleX_*m.radius),",",n(m.y+this.arcScaleY_*m.radius)," ",n(m.xStart),",",n(m.yStart)," ",n(m.xEnd),",",n(m.yEnd));break}if(m){if(ai.x==null||m.x<ai.x){ai.x=m.x}if(an.x==null||m.x>an.x){an.x=m.x}if(ai.y==null||m.y<ai.y){ai.y=m.y}if(an.y==null||m.y>an.y){an.y=m.y}}}am.push(' ">');if(!ao){w(this,am)}else{G(this,am,ai,an)}am.push("</g_vml_:shape>");this.element_.insertAdjacentHTML("beforeEnd",am.join(""))}};function w(m,ag){var j=F(m.strokeStyle);var p=j.color;var Z=j.alpha*m.globalAlpha;var i=m.lineScale_*m.lineWidth;if(i<1){Z*=i}ag.push("<g_vml_:stroke",' opacity="',Z,'"',' joinstyle="',m.lineJoin,'"',' miterlimit="',m.miterLimit,'"',' endcap="',S(m.lineCap),'"',' weight="',i,'px"',' color="',p,'" />')}function G(aq,ai,aK,ar){var aj=aq.fillStyle;var aB=aq.arcScaleX_;var aA=aq.arcScaleY_;var j=ar.x-aK.x;var p=ar.y-aK.y;if(aj instanceof U){var an=0;var aF={x:0,y:0};var ax=0;var am=1;if(aj.type_=="gradient"){var al=aj.x0_/aB;var m=aj.y0_/aA;var ak=aj.x1_/aB;var aM=aj.y1_/aA;var aJ=V(aq,al,m);var aI=V(aq,ak,aM);var ag=aI.x-aJ.x;var Z=aI.y-aJ.y;an=Math.atan2(ag,Z)*180/Math.PI;if(an<0){an+=360}if(an<0.000001){an=0}}else{var aJ=V(aq,aj.x0_,aj.y0_);aF={x:(aJ.x-aK.x)/j,y:(aJ.y-aK.y)/p};j/=aB*d;p/=aA*d;var aD=ab.max(j,p);ax=2*aj.r0_/aD;am=2*aj.r1_/aD-ax}var av=aj.colors_;av.sort(function(aN,i){return aN.offset-i.offset});var ap=av.length;var au=av[0].color;var at=av[ap-1].color;var az=av[0].alpha*aq.globalAlpha;var ay=av[ap-1].alpha*aq.globalAlpha;var aE=[];for(var aH=0;aH<ap;aH++){var ao=av[aH];aE.push(ao.offset*am+ax+" "+ao.color)}ai.push('<g_vml_:fill type="',aj.type_,'"',' method="none" focus="100%"',' color="',au,'"',' color2="',at,'"',' colors="',aE.join(","),'"',' opacity="',ay,'"',' g_o_:opacity2="',az,'"',' angle="',an,'"',' focusposition="',aF.x,",",aF.y,'" />')}else{if(aj instanceof T){if(j&&p){var ah=-aK.x;var aC=-aK.y;ai.push("<g_vml_:fill",' position="',ah/j*aB*aB,",",aC/p*aA*aA,'"',' type="tile"',' src="',aj.src_,'" />')}}else{var aL=F(aq.fillStyle);var aw=aL.color;var aG=aL.alpha*aq.globalAlpha;ai.push('<g_vml_:fill color="',aw,'" opacity="',aG,'" />')}}}q.fill=function(){this.stroke(true)};q.closePath=function(){this.currentPath_.push({type:"close"})};function V(j,Z,p){var i=j.m_;return{x:d*(Z*i[0][0]+p*i[1][0]+i[2][0])-f,y:d*(Z*i[0][1]+p*i[1][1]+i[2][1])-f}}q.save=function(){var i={};v(this,i);this.aStack_.push(i);this.mStack_.push(this.m_);this.m_=J(B(),this.m_)};q.restore=function(){if(this.aStack_.length){v(this.aStack_.pop(),this);this.m_=this.mStack_.pop()}};function h(i){return isFinite(i[0][0])&&isFinite(i[0][1])&&isFinite(i[1][0])&&isFinite(i[1][1])&&isFinite(i[2][0])&&isFinite(i[2][1])}function aa(j,i,p){if(!h(i)){return}j.m_=i;if(p){var Z=i[0][0]*i[1][1]-i[0][1]*i[1][0];j.lineScale_=N(H(Z))}}q.translate=function(m,j){var i=[[1,0,0],[0,1,0],[m,j,1]];aa(this,J(i,this.m_),false)};q.rotate=function(j){var p=A(j);var m=l(j);var i=[[p,m,0],[-m,p,0],[0,0,1]];aa(this,J(i,this.m_),false)};q.scale=function(m,j){this.arcScaleX_*=m;this.arcScaleY_*=j;var i=[[m,0,0],[0,j,0],[0,0,1]];aa(this,J(i,this.m_),true)};q.transform=function(Z,p,ah,ag,j,i){var m=[[Z,p,0],[ah,ag,0],[j,i,1]];aa(this,J(m,this.m_),true)};q.setTransform=function(ag,Z,ai,ah,p,j){var i=[[ag,Z,0],[ai,ah,0],[p,j,1]];aa(this,i,true)};q.drawText_=function(am,ak,aj,ap,ai){var ao=this.m_,at=1000,j=0,ar=at,ah={x:0,y:0},ag=[];var i=u(E(this.font),this.element_);var p=ac(i);var au=this.element_.currentStyle;var Z=this.textAlign.toLowerCase();switch(Z){case"left":case"center":case"right":break;case"end":Z=au.direction=="ltr"?"right":"left";break;case"start":Z=au.direction=="rtl"?"right":"left";break;default:Z="left"}switch(this.textBaseline){case"hanging":case"top":ah.y=i.size/1.75;break;case"middle":break;default:case null:case"alphabetic":case"ideographic":case"bottom":ah.y=-i.size/2.25;break}switch(Z){case"right":j=at;ar=0.05;break;case"center":j=ar=at/2;break}var aq=V(this,ak+ah.x,aj+ah.y);ag.push('<g_vml_:line from="',-j,' 0" to="',ar,' 0.05" ',' coordsize="100 100" coordorigin="0 0"',' filled="',!ai,'" stroked="',!!ai,'" style="position:absolute;width:1px;height:1px;">');if(ai){w(this,ag)}else{G(this,ag,{x:-j,y:0},{x:ar,y:i.size})}var an=ao[0][0].toFixed(3)+","+ao[1][0].toFixed(3)+","+ao[0][1].toFixed(3)+","+ao[1][1].toFixed(3)+",0,0";var al=n(aq.x/d)+","+n(aq.y/d);ag.push('<g_vml_:skew on="t" matrix="',an,'" ',' offset="',al,'" origin="',j,' 0" />','<g_vml_:path textpathok="true" />','<g_vml_:textpath on="true" string="',af(am),'" style="v-text-align:',Z,";font:",af(p),'" /></g_vml_:line>');this.element_.insertAdjacentHTML("beforeEnd",ag.join(""))};q.fillText=function(m,i,p,j){this.drawText_(m,i,p,j,false)};q.strokeText=function(m,i,p,j){this.drawText_(m,i,p,j,true)};q.measureText=function(m){if(!this.textMeasureEl_){var i='<span style="position:absolute;top:-20000px;left:0;padding:0;margin:0;border:none;white-space:pre;"></span>';this.element_.insertAdjacentHTML("beforeEnd",i);this.textMeasureEl_=this.element_.lastChild}var j=this.element_.ownerDocument;this.textMeasureEl_.innerHTML="";this.textMeasureEl_.style.font=this.font;this.textMeasureEl_.appendChild(j.createTextNode(m));return{width:this.textMeasureEl_.offsetWidth}};q.clip=function(){};q.arcTo=function(){};q.createPattern=function(j,i){return new T(j,i)};function U(i){this.type_=i;this.x0_=0;this.y0_=0;this.r0_=0;this.x1_=0;this.y1_=0;this.r1_=0;this.colors_=[]}U.prototype.addColorStop=function(j,i){i=F(i);this.colors_.push({offset:j,color:i.color,alpha:i.alpha})};function T(j,i){Q(j);switch(i){case"repeat":case null:case"":this.repetition_="repeat";break;case"repeat-x":case"repeat-y":case"no-repeat":this.repetition_=i;break;default:O("SYNTAX_ERR")}this.src_=j.src;this.width_=j.width;this.height_=j.height}function O(i){throw new P(i)}function Q(i){if(!i||i.nodeType!=1||i.tagName!="IMG"){O("TYPE_MISMATCH_ERR")}if(i.readyState!="complete"){O("INVALID_STATE_ERR")}}function P(i){this.code=this[i];this.message=i+": DOM Exception "+this.code}var X=P.prototype=new Error;X.INDEX_SIZE_ERR=1;X.DOMSTRING_SIZE_ERR=2;X.HIERARCHY_REQUEST_ERR=3;X.WRONG_DOCUMENT_ERR=4;X.INVALID_CHARACTER_ERR=5;X.NO_DATA_ALLOWED_ERR=6;X.NO_MODIFICATION_ALLOWED_ERR=7;X.NOT_FOUND_ERR=8;X.NOT_SUPPORTED_ERR=9;X.INUSE_ATTRIBUTE_ERR=10;X.INVALID_STATE_ERR=11;X.SYNTAX_ERR=12;X.INVALID_MODIFICATION_ERR=13;X.NAMESPACE_ERR=14;X.INVALID_ACCESS_ERR=15;X.VALIDATION_ERR=16;X.TYPE_MISMATCH_ERR=17;G_vmlCanvasManager=e;CanvasRenderingContext2D=D;CanvasGradient=U;CanvasPattern=T;DOMException=P})()};
\ No newline at end of file
diff --git a/htdocs/Libs/Flot/jquery.flot.min.js b/htdocs/Libs/Flot/jquery.flot.min.js
new file mode 100644
index 0000000..968d3eb
--- /dev/null
+++ b/htdocs/Libs/Flot/jquery.flot.min.js
@@ -0,0 +1,8 @@
+/* Javascript plotting library for jQuery, version 0.8.3.
+
+Copyright (c) 2007-2014 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+*/
+(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);(function($){var hasOwnProperty=Object.prototype.hasOwnProperty;if(!$.fn.detach){$.fn.detach=function(){return this.each(function(){if(this.parentNode){this.parentNode.removeChild(this)}})}}function Canvas(cls,container){var element=container.children("."+cls)[0];if(element==null){element=document.createElement("canvas");element.className=cls;$(element).css({direction:"ltr",position:"absolute",left:0,top:0}).appendTo(container);if(!element.getContext){if(window.G_vmlCanvasManager){element=window.G_vmlCanvasManager.initElement(element)}else{throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.")}}}this.element=element;var context=this.context=element.getContext("2d");var devicePixelRatio=window.devicePixelRatio||1,backingStoreRatio=context.webkitBackingStorePixelRatio||context.mozBackingStorePixelRatio||context.msBackingStorePixelRatio||context.oBackingStorePixelRatio||context.backingStorePixelRatio||1;this.pixelRatio=devicePixelRatio/backingStoreRatio;this.resize(container.width(),container.height());this.textContainer=null;this.text={};this._textCache={}}Canvas.prototype.resize=function(width,height){if(width<=0||height<=0){throw new Error("Invalid dimensions for plot, width = "+width+", height = "+height)}var element=this.element,context=this.context,pixelRatio=this.pixelRatio;if(this.width!=width){element.width=width*pixelRatio;element.style.width=width+"px";this.width=width}if(this.height!=height){element.height=height*pixelRatio;element.style.height=height+"px";this.height=height}context.restore();context.save();context.scale(pixelRatio,pixelRatio)};Canvas.prototype.clear=function(){this.context.clearRect(0,0,this.width,this.height)};Canvas.prototype.render=function(){var cache=this._textCache;for(var layerKey in cache){if(hasOwnProperty.call(cache,layerKey)){var layer=this.getTextLayer(layerKey),layerCache=cache[layerKey];layer.hide();for(var styleKey in layerCache){if(hasOwnProperty.call(layerCache,styleKey)){var styleCache=layerCache[styleKey];for(var key in styleCache){if(hasOwnProperty.call(styleCache,key)){var positions=styleCache[key].positions;for(var i=0,position;position=positions[i];i++){if(position.active){if(!position.rendered){layer.append(position.element);position.rendered=true}}else{positions.splice(i--,1);if(position.rendered){position.element.detach()}}}if(positions.length==0){delete styleCache[key]}}}}}layer.show()}}};Canvas.prototype.getTextLayer=function(classes){var layer=this.text[classes];if(layer==null){if(this.textContainer==null){this.textContainer=$("<div class='flot-text'></div>").css({position:"absolute",top:0,left:0,bottom:0,right:0,"font-size":"smaller",color:"#545454"}).insertAfter(this.element)}layer=this.text[classes]=$("<div></div>").addClass(classes).css({position:"absolute",top:0,left:0,bottom:0,right:0}).appendTo(this.textContainer)}return layer};Canvas.prototype.getTextInfo=function(layer,text,font,angle,width){var textStyle,layerCache,styleCache,info;text=""+text;if(typeof font==="object"){textStyle=font.style+" "+font.variant+" "+font.weight+" "+font.size+"px/"+font.lineHeight+"px "+font.family}else{textStyle=font}layerCache=this._textCache[layer];if(layerCache==null){layerCache=this._textCache[layer]={}}styleCache=layerCache[textStyle];if(styleCache==null){styleCache=layerCache[textStyle]={}}info=styleCache[text];if(info==null){var element=$("<div></div>").html(text).css({position:"absolute","max-width":width,top:-9999}).appendTo(this.getTextLayer(layer));if(typeof font==="object"){element.css({font:textStyle,color:font.color})}else if(typeof font==="string"){element.addClass(font)}info=styleCache[text]={width:element.outerWidth(true),height:element.outerHeight(true),element:element,positions:[]};element.detach()}return info};Canvas.prototype.addText=function(layer,x,y,text,font,angle,width,halign,valign){var info=this.getTextInfo(layer,text,font,angle,width),positions=info.positions;if(halign=="center"){x-=info.width/2}else if(halign=="right"){x-=info.width}if(valign=="middle"){y-=info.height/2}else if(valign=="bottom"){y-=info.height}for(var i=0,position;position=positions[i];i++){if(position.x==x&&position.y==y){position.active=true;return}}position={active:true,rendered:false,element:positions.length?info.element.clone():info.element,x:x,y:y};positions.push(position);position.element.css({top:Math.round(y),left:Math.round(x),"text-align":halign})};Canvas.prototype.removeText=function(layer,x,y,text,font,angle){if(text==null){var layerCache=this._textCache[layer];if(layerCache!=null){for(var styleKey in layerCache){if(hasOwnProperty.call(layerCache,styleKey)){var styleCache=layerCache[styleKey];for(var key in styleCache){if(hasOwnProperty.call(styleCache,key)){var positions=styleCache[key].positions;for(var i=0,position;position=positions[i];i++){position.active=false}}}}}}}else{var positions=this.getTextInfo(layer,text,font,angle).positions;for(var i=0,position;position=positions[i];i++){if(position.x==x&&position.y==y){position.active=false}}}};function Plot(placeholder,data_,options_,plugins){var series=[],options={colors:["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"],legend:{show:true,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:.85,sorted:null},xaxis:{show:null,position:"bottom",mode:null,font:null,color:null,tickColor:null,transform:null,inverseTransform:null,min:null,max:null,autoscaleMargin:null,ticks:null,tickFormatter:null,labelWidth:null,labelHeight:null,reserveSpace:null,tickLength:null,alignTicksWithAxis:null,tickDecimals:null,tickSize:null,minTickSize:null},yaxis:{autoscaleMargin:.02,position:"left"},xaxes:[],yaxes:[],series:{points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#ffffff",symbol:"circle"},lines:{lineWidth:2,fill:false,fillColor:null,steps:false},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,align:"left",horizontal:false,zero:true},shadowSize:3,highlightColor:null},grid:{show:true,aboveData:false,color:"#545454",backgroundColor:null,borderColor:null,tickColor:null,margin:0,labelMargin:5,axisMargin:8,borderWidth:2,minBorderMargin:null,markings:null,markingsColor:"#f4f4f4",markingsLineWidth:2,clickable:false,hoverable:false,autoHighlight:true,mouseActiveRadius:10},interaction:{redrawOverlayInterval:1e3/60},hooks:{}},surface=null,overlay=null,eventHolder=null,ctx=null,octx=null,xaxes=[],yaxes=[],plotOffset={left:0,right:0,top:0,bottom:0},plotWidth=0,plotHeight=0,hooks={processOptions:[],processRawData:[],processDatapoints:[],processOffset:[],drawBackground:[],drawSeries:[],draw:[],bindEvents:[],drawOverlay:[],shutdown:[]},plot=this;plot.setData=setData;plot.setupGrid=setupGrid;plot.draw=draw;plot.getPlaceholder=function(){return placeholder};plot.getCanvas=function(){return surface.element};plot.getPlotOffset=function(){return plotOffset};plot.width=function(){return plotWidth};plot.height=function(){return plotHeight};plot.offset=function(){var o=eventHolder.offset();o.left+=plotOffset.left;o.top+=plotOffset.top;return o};plot.getData=function(){return series};plot.getAxes=function(){var res={},i;$.each(xaxes.concat(yaxes),function(_,axis){if(axis)res[axis.direction+(axis.n!=1?axis.n:"")+"axis"]=axis});return res};plot.getXAxes=function(){return xaxes};plot.getYAxes=function(){return yaxes};plot.c2p=canvasToAxisCoords;plot.p2c=axisToCanvasCoords;plot.getOptions=function(){return options};plot.highlight=highlight;plot.unhighlight=unhighlight;plot.triggerRedrawOverlay=triggerRedrawOverlay;plot.pointOffset=function(point){return{left:parseInt(xaxes[axisNumber(point,"x")-1].p2c(+point.x)+plotOffset.left,10),top:parseInt(yaxes[axisNumber(point,"y")-1].p2c(+point.y)+plotOffset.top,10)}};plot.shutdown=shutdown;plot.destroy=function(){shutdown();placeholder.removeData("plot").empty();series=[];options=null;surface=null;overlay=null;eventHolder=null;ctx=null;octx=null;xaxes=[];yaxes=[];hooks=null;highlights=[];plot=null};plot.resize=function(){var width=placeholder.width(),height=placeholder.height();surface.resize(width,height);overlay.resize(width,height)};plot.hooks=hooks;initPlugins(plot);parseOptions(options_);setupCanvases();setData(data_);setupGrid();draw();bindEvents();function executeHooks(hook,args){args=[plot].concat(args);for(var i=0;i<hook.length;++i)hook[i].apply(this,args)}function initPlugins(){var classes={Canvas:Canvas};for(var i=0;i<plugins.length;++i){var p=plugins[i];p.init(plot,classes);if(p.options)$.extend(true,options,p.options)}}function parseOptions(opts){$.extend(true,options,opts);if(opts&&opts.colors){options.colors=opts.colors}if(options.xaxis.color==null)options.xaxis.color=$.color.parse(options.grid.color).scale("a",.22).toString();if(options.yaxis.color==null)options.yaxis.color=$.color.parse(options.grid.color).scale("a",.22).toString();if(options.xaxis.tickColor==null)options.xaxis.tickColor=options.grid.tickColor||options.xaxis.color;if(options.yaxis.tickColor==null)options.yaxis.tickColor=options.grid.tickColor||options.yaxis.color;if(options.grid.borderColor==null)options.grid.borderColor=options.grid.color;if(options.grid.tickColor==null)options.grid.tickColor=$.color.parse(options.grid.color).scale("a",.22).toString();var i,axisOptions,axisCount,fontSize=placeholder.css("font-size"),fontSizeDefault=fontSize?+fontSize.replace("px",""):13,fontDefaults={style:placeholder.css("font-style"),size:Math.round(.8*fontSizeDefault),variant:placeholder.css("font-variant"),weight:placeholder.css("font-weight"),family:placeholder.css("font-family")};axisCount=options.xaxes.length||1;for(i=0;i<axisCount;++i){axisOptions=options.xaxes[i];if(axisOptions&&!axisOptions.tickColor){axisOptions.tickColor=axisOptions.color}axisOptions=$.extend(true,{},options.xaxis,axisOptions);options.xaxes[i]=axisOptions;if(axisOptions.font){axisOptions.font=$.extend({},fontDefaults,axisOptions.font);if(!axisOptions.font.color){axisOptions.font.color=axisOptions.color}if(!axisOptions.font.lineHeight){axisOptions.font.lineHeight=Math.round(axisOptions.font.size*1.15)}}}axisCount=options.yaxes.length||1;for(i=0;i<axisCount;++i){axisOptions=options.yaxes[i];if(axisOptions&&!axisOptions.tickColor){axisOptions.tickColor=axisOptions.color}axisOptions=$.extend(true,{},options.yaxis,axisOptions);options.yaxes[i]=axisOptions;if(axisOptions.font){axisOptions.font=$.extend({},fontDefaults,axisOptions.font);if(!axisOptions.font.color){axisOptions.font.color=axisOptions.color}if(!axisOptions.font.lineHeight){axisOptions.font.lineHeight=Math.round(axisOptions.font.size*1.15)}}}if(options.xaxis.noTicks&&options.xaxis.ticks==null)options.xaxis.ticks=options.xaxis.noTicks;if(options.yaxis.noTicks&&options.yaxis.ticks==null)options.yaxis.ticks=options.yaxis.noTicks;if(options.x2axis){options.xaxes[1]=$.extend(true,{},options.xaxis,options.x2axis);options.xaxes[1].position="top";if(options.x2axis.min==null){options.xaxes[1].min=null}if(options.x2axis.max==null){options.xaxes[1].max=null}}if(options.y2axis){options.yaxes[1]=$.extend(true,{},options.yaxis,options.y2axis);options.yaxes[1].position="right";if(options.y2axis.min==null){options.yaxes[1].min=null}if(options.y2axis.max==null){options.yaxes[1].max=null}}if(options.grid.coloredAreas)options.grid.markings=options.grid.coloredAreas;if(options.grid.coloredAreasColor)options.grid.markingsColor=options.grid.coloredAreasColor;if(options.lines)$.extend(true,options.series.lines,options.lines);if(options.points)$.extend(true,options.series.points,options.points);if(options.bars)$.extend(true,options.series.bars,options.bars);if(options.shadowSize!=null)options.series.shadowSize=options.shadowSize;if(options.highlightColor!=null)options.series.highlightColor=options.highlightColor;for(i=0;i<options.xaxes.length;++i)getOrCreateAxis(xaxes,i+1).options=options.xaxes[i];for(i=0;i<options.yaxes.length;++i)getOrCreateAxis(yaxes,i+1).options=options.yaxes[i];for(var n in hooks)if(options.hooks[n]&&options.hooks[n].length)hooks[n]=hooks[n].concat(options.hooks[n]);executeHooks(hooks.processOptions,[options])}function setData(d){series=parseData(d);fillInSeriesOptions();processData()}function parseData(d){var res=[];for(var i=0;i<d.length;++i){var s=$.extend(true,{},options.series);if(d[i].data!=null){s.data=d[i].data;delete d[i].data;$.extend(true,s,d[i]);d[i].data=s.data}else s.data=d[i];res.push(s)}return res}function axisNumber(obj,coord){var a=obj[coord+"axis"];if(typeof a=="object")a=a.n;if(typeof a!="number")a=1;return a}function allAxes(){return $.grep(xaxes.concat(yaxes),function(a){return a})}function canvasToAxisCoords(pos){var res={},i,axis;for(i=0;i<xaxes.length;++i){axis=xaxes[i];if(axis&&axis.used)res["x"+axis.n]=axis.c2p(pos.left)}for(i=0;i<yaxes.length;++i){axis=yaxes[i];if(axis&&axis.used)res["y"+axis.n]=axis.c2p(pos.top)}if(res.x1!==undefined)res.x=res.x1;if(res.y1!==undefined)res.y=res.y1;return res}function axisToCanvasCoords(pos){var res={},i,axis,key;for(i=0;i<xaxes.length;++i){axis=xaxes[i];if(axis&&axis.used){key="x"+axis.n;if(pos[key]==null&&axis.n==1)key="x";if(pos[key]!=null){res.left=axis.p2c(pos[key]);break}}}for(i=0;i<yaxes.length;++i){axis=yaxes[i];if(axis&&axis.used){key="y"+axis.n;if(pos[key]==null&&axis.n==1)key="y";if(pos[key]!=null){res.top=axis.p2c(pos[key]);break}}}return res}function getOrCreateAxis(axes,number){if(!axes[number-1])axes[number-1]={n:number,direction:axes==xaxes?"x":"y",options:$.extend(true,{},axes==xaxes?options.xaxis:options.yaxis)};return axes[number-1]}function fillInSeriesOptions(){var neededColors=series.length,maxIndex=-1,i;for(i=0;i<series.length;++i){var sc=series[i].color;if(sc!=null){neededColors--;if(typeof sc=="number"&&sc>maxIndex){maxIndex=sc}}}if(neededColors<=maxIndex){neededColors=maxIndex+1}var c,colors=[],colorPool=options.colors,colorPoolSize=colorPool.length,variation=0;for(i=0;i<neededColors;i++){c=$.color.parse(colorPool[i%colorPoolSize]||"#666");if(i%colorPoolSize==0&&i){if(variation>=0){if(variation<.5){variation=-variation-.2}else variation=0}else variation=-variation}colors[i]=c.scale("rgb",1+variation)}var colori=0,s;for(i=0;i<series.length;++i){s=series[i];if(s.color==null){s.color=colors[colori].toString();++colori}else if(typeof s.color=="number")s.color=colors[s.color].toString();if(s.lines.show==null){var v,show=true;for(v in s)if(s[v]&&s[v].show){show=false;break}if(show)s.lines.show=true}if(s.lines.zero==null){s.lines.zero=!!s.lines.fill}s.xaxis=getOrCreateAxis(xaxes,axisNumber(s,"x"));s.yaxis=getOrCreateAxis(yaxes,axisNumber(s,"y"))}}function processData(){var topSentry=Number.POSITIVE_INFINITY,bottomSentry=Number.NEGATIVE_INFINITY,fakeInfinity=Number.MAX_VALUE,i,j,k,m,length,s,points,ps,x,y,axis,val,f,p,data,format;function updateAxis(axis,min,max){if(min<axis.datamin&&min!=-fakeInfinity)axis.datamin=min;if(max>axis.datamax&&max!=fakeInfinity)axis.datamax=max}$.each(allAxes(),function(_,axis){axis.datamin=topSentry;axis.datamax=bottomSentry;axis.used=false});for(i=0;i<series.length;++i){s=series[i];s.datapoints={points:[]};executeHooks(hooks.processRawData,[s,s.data,s.datapoints])}for(i=0;i<series.length;++i){s=series[i];data=s.data;format=s.datapoints.format;if(!format){format=[];format.push({x:true,number:true,required:true});format.push({y:true,number:true,required:true});if(s.bars.show||s.lines.show&&s.lines.fill){var autoscale=!!(s.bars.show&&s.bars.zero||s.lines.show&&s.lines.zero);format.push({y:true,number:true,required:false,defaultValue:0,autoscale:autoscale});if(s.bars.horizontal){delete format[format.length-1].y;format[format.length-1].x=true}}s.datapoints.format=format}if(s.datapoints.pointsize!=null)continue;s.datapoints.pointsize=format.length;ps=s.datapoints.pointsize;points=s.datapoints.points;var insertSteps=s.lines.show&&s.lines.steps;s.xaxis.used=s.yaxis.used=true;for(j=k=0;j<data.length;++j,k+=ps){p=data[j];var nullify=p==null;if(!nullify){for(m=0;m<ps;++m){val=p[m];f=format[m];if(f){if(f.number&&val!=null){val=+val;if(isNaN(val))val=null;else if(val==Infinity)val=fakeInfinity;else if(val==-Infinity)val=-fakeInfinity}if(val==null){if(f.required)nullify=true;if(f.defaultValue!=null)val=f.defaultValue}}points[k+m]=val}}if(nullify){for(m=0;m<ps;++m){val=points[k+m];if(val!=null){f=format[m];if(f.autoscale!==false){if(f.x){updateAxis(s.xaxis,val,val)}if(f.y){updateAxis(s.yaxis,val,val)}}}points[k+m]=null}}else{if(insertSteps&&k>0&&points[k-ps]!=null&&points[k-ps]!=points[k]&&points[k-ps+1]!=points[k+1]){for(m=0;m<ps;++m)points[k+ps+m]=points[k+m];points[k+1]=points[k-ps+1];k+=ps}}}}for(i=0;i<series.length;++i){s=series[i];executeHooks(hooks.processDatapoints,[s,s.datapoints])}for(i=0;i<series.length;++i){s=series[i];points=s.datapoints.points;ps=s.datapoints.pointsize;format=s.datapoints.format;var xmin=topSentry,ymin=topSentry,xmax=bottomSentry,ymax=bottomSentry;for(j=0;j<points.length;j+=ps){if(points[j]==null)continue;for(m=0;m<ps;++m){val=points[j+m];f=format[m];if(!f||f.autoscale===false||val==fakeInfinity||val==-fakeInfinity)continue;if(f.x){if(val<xmin)xmin=val;if(val>xmax)xmax=val}if(f.y){if(val<ymin)ymin=val;if(val>ymax)ymax=val}}}if(s.bars.show){var delta;switch(s.bars.align){case"left":delta=0;break;case"right":delta=-s.bars.barWidth;break;default:delta=-s.bars.barWidth/2}if(s.bars.horizontal){ymin+=delta;ymax+=delta+s.bars.barWidth}else{xmin+=delta;xmax+=delta+s.bars.barWidth}}updateAxis(s.xaxis,xmin,xmax);updateAxis(s.yaxis,ymin,ymax)}$.each(allAxes(),function(_,axis){if(axis.datamin==topSentry)axis.datamin=null;if(axis.datamax==bottomSentry)axis.datamax=null})}function setupCanvases(){placeholder.css("padding",0).children().filter(function(){return!$(this).hasClass("flot-overlay")&&!$(this).hasClass("flot-base")}).remove();if(placeholder.css("position")=="static")placeholder.css("position","relative");surface=new Canvas("flot-base",placeholder);overlay=new Canvas("flot-overlay",placeholder);ctx=surface.context;octx=overlay.context;eventHolder=$(overlay.element).unbind();var existing=placeholder.data("plot");if(existing){existing.shutdown();overlay.clear()}placeholder.data("plot",plot)}function bindEvents(){if(options.grid.hoverable){eventHolder.mousemove(onMouseMove);eventHolder.bind("mouseleave",onMouseLeave)}if(options.grid.clickable)eventHolder.click(onClick);executeHooks(hooks.bindEvents,[eventHolder])}function shutdown(){if(redrawTimeout)clearTimeout(redrawTimeout);eventHolder.unbind("mousemove",onMouseMove);eventHolder.unbind("mouseleave",onMouseLeave);eventHolder.unbind("click",onClick);executeHooks(hooks.shutdown,[eventHolder])}function setTransformationHelpers(axis){function identity(x){return x}var s,m,t=axis.options.transform||identity,it=axis.options.inverseTransform;if(axis.direction=="x"){s=axis.scale=plotWidth/Math.abs(t(axis.max)-t(axis.min));m=Math.min(t(axis.max),t(axis.min))}else{s=axis.scale=plotHeight/Math.abs(t(axis.max)-t(axis.min));s=-s;m=Math.max(t(axis.max),t(axis.min))}if(t==identity)axis.p2c=function(p){return(p-m)*s};else axis.p2c=function(p){return(t(p)-m)*s};if(!it)axis.c2p=function(c){return m+c/s};else axis.c2p=function(c){return it(m+c/s)}}function measureTickLabels(axis){var opts=axis.options,ticks=axis.ticks||[],labelWidth=opts.labelWidth||0,labelHeight=opts.labelHeight||0,maxWidth=labelWidth||(axis.direction=="x"?Math.floor(surface.width/(ticks.length||1)):null),legacyStyles=axis.direction+"Axis "+axis.direction+axis.n+"Axis",layer="flot-"+axis.direction+"-axis flot-"+axis.direction+axis.n+"-axis "+legacyStyles,font=opts.font||"flot-tick-label tickLabel";for(var i=0;i<ticks.length;++i){var t=ticks[i];if(!t.label)continue;var info=surface.getTextInfo(layer,t.label,font,null,maxWidth);labelWidth=Math.max(labelWidth,info.width);labelHeight=Math.max(labelHeight,info.height)}axis.labelWidth=opts.labelWidth||labelWidth;axis.labelHeight=opts.labelHeight||labelHeight}function allocateAxisBoxFirstPhase(axis){var lw=axis.labelWidth,lh=axis.labelHeight,pos=axis.options.position,isXAxis=axis.direction==="x",tickLength=axis.options.tickLength,axisMargin=options.grid.axisMargin,padding=options.grid.labelMargin,innermost=true,outermost=true,first=true,found=false;$.each(isXAxis?xaxes:yaxes,function(i,a){if(a&&(a.show||a.reserveSpace)){if(a===axis){found=true}else if(a.options.position===pos){if(found){outermost=false}else{innermost=false}}if(!found){first=false}}});if(outermost){axisMargin=0}if(tickLength==null){tickLength=first?"full":5}if(!isNaN(+tickLength))padding+=+tickLength;if(isXAxis){lh+=padding;if(pos=="bottom"){plotOffset.bottom+=lh+axisMargin;axis.box={top:surface.height-plotOffset.bottom,height:lh}}else{axis.box={top:plotOffset.top+axisMargin,height:lh};plotOffset.top+=lh+axisMargin}}else{lw+=padding;if(pos=="left"){axis.box={left:plotOffset.left+axisMargin,width:lw};plotOffset.left+=lw+axisMargin}else{plotOffset.right+=lw+axisMargin;axis.box={left:surface.width-plotOffset.right,width:lw}}}axis.position=pos;axis.tickLength=tickLength;axis.box.padding=padding;axis.innermost=innermost}function allocateAxisBoxSecondPhase(axis){if(axis.direction=="x"){axis.box.left=plotOffset.left-axis.labelWidth/2;axis.box.width=surface.width-plotOffset.left-plotOffset.right+axis.labelWidth}else{axis.box.top=plotOffset.top-axis.labelHeight/2;axis.box.height=surface.height-plotOffset.bottom-plotOffset.top+axis.labelHeight}}function adjustLayoutForThingsStickingOut(){var minMargin=options.grid.minBorderMargin,axis,i;if(minMargin==null){minMargin=0;for(i=0;i<series.length;++i)minMargin=Math.max(minMargin,2*(series[i].points.radius+series[i].points.lineWidth/2))}var margins={left:minMargin,right:minMargin,top:minMargin,bottom:minMargin};$.each(allAxes(),function(_,axis){if(axis.reserveSpace&&axis.ticks&&axis.ticks.length){if(axis.direction==="x"){margins.left=Math.max(margins.left,axis.labelWidth/2);margins.right=Math.max(margins.right,axis.labelWidth/2)}else{margins.bottom=Math.max(margins.bottom,axis.labelHeight/2);margins.top=Math.max(margins.top,axis.labelHeight/2)}}});plotOffset.left=Math.ceil(Math.max(margins.left,plotOffset.left));plotOffset.right=Math.ceil(Math.max(margins.right,plotOffset.right));plotOffset.top=Math.ceil(Math.max(margins.top,plotOffset.top));plotOffset.bottom=Math.ceil(Math.max(margins.bottom,plotOffset.bottom))}function setupGrid(){var i,axes=allAxes(),showGrid=options.grid.show;for(var a in plotOffset){var margin=options.grid.margin||0;plotOffset[a]=typeof margin=="number"?margin:margin[a]||0}executeHooks(hooks.processOffset,[plotOffset]);for(var a in plotOffset){if(typeof options.grid.borderWidth=="object"){plotOffset[a]+=showGrid?options.grid.borderWidth[a]:0}else{plotOffset[a]+=showGrid?options.grid.borderWidth:0}}$.each(axes,function(_,axis){var axisOpts=axis.options;axis.show=axisOpts.show==null?axis.used:axisOpts.show;axis.reserveSpace=axisOpts.reserveSpace==null?axis.show:axisOpts.reserveSpace;setRange(axis)});if(showGrid){var allocatedAxes=$.grep(axes,function(axis){return axis.show||axis.reserveSpace});$.each(allocatedAxes,function(_,axis){setupTickGeneration(axis);setTicks(axis);snapRangeToTicks(axis,axis.ticks);measureTickLabels(axis)});for(i=allocatedAxes.length-1;i>=0;--i)allocateAxisBoxFirstPhase(allocatedAxes[i]);adjustLayoutForThingsStickingOut();$.each(allocatedAxes,function(_,axis){allocateAxisBoxSecondPhase(axis)})}plotWidth=surface.width-plotOffset.left-plotOffset.right;plotHeight=surface.height-plotOffset.bottom-plotOffset.top;$.each(axes,function(_,axis){setTransformationHelpers(axis)});if(showGrid){drawAxisLabels()}insertLegend()}function setRange(axis){var opts=axis.options,min=+(opts.min!=null?opts.min:axis.datamin),max=+(opts.max!=null?opts.max:axis.datamax),delta=max-min;if(delta==0){var widen=max==0?1:.01;if(opts.min==null)min-=widen;if(opts.max==null||opts.min!=null)max+=widen}else{var margin=opts.autoscaleMargin;if(margin!=null){if(opts.min==null){min-=delta*margin;if(min<0&&axis.datamin!=null&&axis.datamin>=0)min=0}if(opts.max==null){max+=delta*margin;if(max>0&&axis.datamax!=null&&axis.datamax<=0)max=0}}}axis.min=min;axis.max=max}function setupTickGeneration(axis){var opts=axis.options;var noTicks;if(typeof opts.ticks=="number"&&opts.ticks>0)noTicks=opts.ticks;else noTicks=.3*Math.sqrt(axis.direction=="x"?surface.width:surface.height);var delta=(axis.max-axis.min)/noTicks,dec=-Math.floor(Math.log(delta)/Math.LN10),maxDec=opts.tickDecimals;if(maxDec!=null&&dec>maxDec){dec=maxDec}var magn=Math.pow(10,-dec),norm=delta/magn,size;if(norm<1.5){size=1}else if(norm<3){size=2;if(norm>2.25&&(maxDec==null||dec+1<=maxDec)){size=2.5;++dec}}else if(norm<7.5){size=5}else{size=10}size*=magn;if(opts.minTickSize!=null&&size<opts.minTickSize){size=opts.minTickSize}axis.delta=delta;axis.tickDecimals=Math.max(0,maxDec!=null?maxDec:dec);axis.tickSize=opts.tickSize||size;if(opts.mode=="time"&&!axis.tickGenerator){throw new Error("Time mode requires the flot.time plugin.")}if(!axis.tickGenerator){axis.tickGenerator=function(axis){var ticks=[],start=floorInBase(axis.min,axis.tickSize),i=0,v=Number.NaN,prev;do{prev=v;v=start+i*axis.tickSize;ticks.push(v);++i}while(v<axis.max&&v!=prev);return ticks};axis.tickFormatter=function(value,axis){var factor=axis.tickDecimals?Math.pow(10,axis.tickDecimals):1;var formatted=""+Math.round(value*factor)/factor;if(axis.tickDecimals!=null){var decimal=formatted.indexOf(".");var precision=decimal==-1?0:formatted.length-decimal-1;if(precision<axis.tickDecimals){return(precision?formatted:formatted+".")+(""+factor).substr(1,axis.tickDecimals-precision)}}return formatted}}if($.isFunction(opts.tickFormatter))axis.tickFormatter=function(v,axis){return""+opts.tickFormatter(v,axis)};if(opts.alignTicksWithAxis!=null){var otherAxis=(axis.direction=="x"?xaxes:yaxes)[opts.alignTicksWithAxis-1];if(otherAxis&&otherAxis.used&&otherAxis!=axis){var niceTicks=axis.tickGenerator(axis);if(niceTicks.length>0){if(opts.min==null)axis.min=Math.min(axis.min,niceTicks[0]);if(opts.max==null&&niceTicks.length>1)axis.max=Math.max(axis.max,niceTicks[niceTicks.length-1])}axis.tickGenerator=function(axis){var ticks=[],v,i;for(i=0;i<otherAxis.ticks.length;++i){v=(otherAxis.ticks[i].v-otherAxis.min)/(otherAxis.max-otherAxis.min);v=axis.min+v*(axis.max-axis.min);ticks.push(v)}return ticks};if(!axis.mode&&opts.tickDecimals==null){var extraDec=Math.max(0,-Math.floor(Math.log(axis.delta)/Math.LN10)+1),ts=axis.tickGenerator(axis);if(!(ts.length>1&&/\..*0$/.test((ts[1]-ts[0]).toFixed(extraDec))))axis.tickDecimals=extraDec}}}}function setTicks(axis){var oticks=axis.options.ticks,ticks=[];if(oticks==null||typeof oticks=="number"&&oticks>0)ticks=axis.tickGenerator(axis);else if(oticks){if($.isFunction(oticks))ticks=oticks(axis);else ticks=oticks}var i,v;axis.ticks=[];for(i=0;i<ticks.length;++i){var label=null;var t=ticks[i];if(typeof t=="object"){v=+t[0];if(t.length>1)label=t[1]}else v=+t;if(label==null)label=axis.tickFormatter(v,axis);if(!isNaN(v))axis.ticks.push({v:v,label:label})}}function snapRangeToTicks(axis,ticks){if(axis.options.autoscaleMargin&&ticks.length>0){if(axis.options.min==null)axis.min=Math.min(axis.min,ticks[0].v);if(axis.options.max==null&&ticks.length>1)axis.max=Math.max(axis.max,ticks[ticks.length-1].v)}}function draw(){surface.clear();executeHooks(hooks.drawBackground,[ctx]);var grid=options.grid;if(grid.show&&grid.backgroundColor)drawBackground();if(grid.show&&!grid.aboveData){drawGrid()}for(var i=0;i<series.length;++i){executeHooks(hooks.drawSeries,[ctx,series[i]]);drawSeries(series[i])}executeHooks(hooks.draw,[ctx]);if(grid.show&&grid.aboveData){drawGrid()}surface.render();triggerRedrawOverlay()}function extractRange(ranges,coord){var axis,from,to,key,axes=allAxes();for(var i=0;i<axes.length;++i){axis=axes[i];if(axis.direction==coord){key=coord+axis.n+"axis";if(!ranges[key]&&axis.n==1)key=coord+"axis";if(ranges[key]){from=ranges[key].from;to=ranges[key].to;break}}}if(!ranges[key]){axis=coord=="x"?xaxes[0]:yaxes[0];from=ranges[coord+"1"];to=ranges[coord+"2"]}if(from!=null&&to!=null&&from>to){var tmp=from;from=to;to=tmp}return{from:from,to:to,axis:axis}}function drawBackground(){ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.fillStyle=getColorOrGradient(options.grid.backgroundColor,plotHeight,0,"rgba(255, 255, 255, 0)");ctx.fillRect(0,0,plotWidth,plotHeight);ctx.restore()}function drawGrid(){var i,axes,bw,bc;ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var markings=options.grid.markings;if(markings){if($.isFunction(markings)){axes=plot.getAxes();axes.xmin=axes.xaxis.min;axes.xmax=axes.xaxis.max;axes.ymin=axes.yaxis.min;axes.ymax=axes.yaxis.max;markings=markings(axes)}for(i=0;i<markings.length;++i){var m=markings[i],xrange=extractRange(m,"x"),yrange=extractRange(m,"y");if(xrange.from==null)xrange.from=xrange.axis.min;if(xrange.to==null)xrange.to=xrange.axis.max;
+if(yrange.from==null)yrange.from=yrange.axis.min;if(yrange.to==null)yrange.to=yrange.axis.max;if(xrange.to<xrange.axis.min||xrange.from>xrange.axis.max||yrange.to<yrange.axis.min||yrange.from>yrange.axis.max)continue;xrange.from=Math.max(xrange.from,xrange.axis.min);xrange.to=Math.min(xrange.to,xrange.axis.max);yrange.from=Math.max(yrange.from,yrange.axis.min);yrange.to=Math.min(yrange.to,yrange.axis.max);var xequal=xrange.from===xrange.to,yequal=yrange.from===yrange.to;if(xequal&&yequal){continue}xrange.from=Math.floor(xrange.axis.p2c(xrange.from));xrange.to=Math.floor(xrange.axis.p2c(xrange.to));yrange.from=Math.floor(yrange.axis.p2c(yrange.from));yrange.to=Math.floor(yrange.axis.p2c(yrange.to));if(xequal||yequal){var lineWidth=m.lineWidth||options.grid.markingsLineWidth,subPixel=lineWidth%2?.5:0;ctx.beginPath();ctx.strokeStyle=m.color||options.grid.markingsColor;ctx.lineWidth=lineWidth;if(xequal){ctx.moveTo(xrange.to+subPixel,yrange.from);ctx.lineTo(xrange.to+subPixel,yrange.to)}else{ctx.moveTo(xrange.from,yrange.to+subPixel);ctx.lineTo(xrange.to,yrange.to+subPixel)}ctx.stroke()}else{ctx.fillStyle=m.color||options.grid.markingsColor;ctx.fillRect(xrange.from,yrange.to,xrange.to-xrange.from,yrange.from-yrange.to)}}}axes=allAxes();bw=options.grid.borderWidth;for(var j=0;j<axes.length;++j){var axis=axes[j],box=axis.box,t=axis.tickLength,x,y,xoff,yoff;if(!axis.show||axis.ticks.length==0)continue;ctx.lineWidth=1;if(axis.direction=="x"){x=0;if(t=="full")y=axis.position=="top"?0:plotHeight;else y=box.top-plotOffset.top+(axis.position=="top"?box.height:0)}else{y=0;if(t=="full")x=axis.position=="left"?0:plotWidth;else x=box.left-plotOffset.left+(axis.position=="left"?box.width:0)}if(!axis.innermost){ctx.strokeStyle=axis.options.color;ctx.beginPath();xoff=yoff=0;if(axis.direction=="x")xoff=plotWidth+1;else yoff=plotHeight+1;if(ctx.lineWidth==1){if(axis.direction=="x"){y=Math.floor(y)+.5}else{x=Math.floor(x)+.5}}ctx.moveTo(x,y);ctx.lineTo(x+xoff,y+yoff);ctx.stroke()}ctx.strokeStyle=axis.options.tickColor;ctx.beginPath();for(i=0;i<axis.ticks.length;++i){var v=axis.ticks[i].v;xoff=yoff=0;if(isNaN(v)||v<axis.min||v>axis.max||t=="full"&&(typeof bw=="object"&&bw[axis.position]>0||bw>0)&&(v==axis.min||v==axis.max))continue;if(axis.direction=="x"){x=axis.p2c(v);yoff=t=="full"?-plotHeight:t;if(axis.position=="top")yoff=-yoff}else{y=axis.p2c(v);xoff=t=="full"?-plotWidth:t;if(axis.position=="left")xoff=-xoff}if(ctx.lineWidth==1){if(axis.direction=="x")x=Math.floor(x)+.5;else y=Math.floor(y)+.5}ctx.moveTo(x,y);ctx.lineTo(x+xoff,y+yoff)}ctx.stroke()}if(bw){bc=options.grid.borderColor;if(typeof bw=="object"||typeof bc=="object"){if(typeof bw!=="object"){bw={top:bw,right:bw,bottom:bw,left:bw}}if(typeof bc!=="object"){bc={top:bc,right:bc,bottom:bc,left:bc}}if(bw.top>0){ctx.strokeStyle=bc.top;ctx.lineWidth=bw.top;ctx.beginPath();ctx.moveTo(0-bw.left,0-bw.top/2);ctx.lineTo(plotWidth,0-bw.top/2);ctx.stroke()}if(bw.right>0){ctx.strokeStyle=bc.right;ctx.lineWidth=bw.right;ctx.beginPath();ctx.moveTo(plotWidth+bw.right/2,0-bw.top);ctx.lineTo(plotWidth+bw.right/2,plotHeight);ctx.stroke()}if(bw.bottom>0){ctx.strokeStyle=bc.bottom;ctx.lineWidth=bw.bottom;ctx.beginPath();ctx.moveTo(plotWidth+bw.right,plotHeight+bw.bottom/2);ctx.lineTo(0,plotHeight+bw.bottom/2);ctx.stroke()}if(bw.left>0){ctx.strokeStyle=bc.left;ctx.lineWidth=bw.left;ctx.beginPath();ctx.moveTo(0-bw.left/2,plotHeight+bw.bottom);ctx.lineTo(0-bw.left/2,0);ctx.stroke()}}else{ctx.lineWidth=bw;ctx.strokeStyle=options.grid.borderColor;ctx.strokeRect(-bw/2,-bw/2,plotWidth+bw,plotHeight+bw)}}ctx.restore()}function drawAxisLabels(){$.each(allAxes(),function(_,axis){var box=axis.box,legacyStyles=axis.direction+"Axis "+axis.direction+axis.n+"Axis",layer="flot-"+axis.direction+"-axis flot-"+axis.direction+axis.n+"-axis "+legacyStyles,font=axis.options.font||"flot-tick-label tickLabel",tick,x,y,halign,valign;surface.removeText(layer);if(!axis.show||axis.ticks.length==0)return;for(var i=0;i<axis.ticks.length;++i){tick=axis.ticks[i];if(!tick.label||tick.v<axis.min||tick.v>axis.max)continue;if(axis.direction=="x"){halign="center";x=plotOffset.left+axis.p2c(tick.v);if(axis.position=="bottom"){y=box.top+box.padding}else{y=box.top+box.height-box.padding;valign="bottom"}}else{valign="middle";y=plotOffset.top+axis.p2c(tick.v);if(axis.position=="left"){x=box.left+box.width-box.padding;halign="right"}else{x=box.left+box.padding}}surface.addText(layer,x,y,tick.label,font,null,null,halign,valign)}})}function drawSeries(series){if(series.lines.show)drawSeriesLines(series);if(series.bars.show)drawSeriesBars(series);if(series.points.show)drawSeriesPoints(series)}function drawSeriesLines(series){function plotLine(datapoints,xoffset,yoffset,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize,prevx=null,prevy=null;ctx.beginPath();for(var i=ps;i<points.length;i+=ps){var x1=points[i-ps],y1=points[i-ps+1],x2=points[i],y2=points[i+1];if(x1==null||x2==null)continue;if(y1<=y2&&y1<axisy.min){if(y2<axisy.min)continue;x1=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.min}else if(y2<=y1&&y2<axisy.min){if(y1<axisy.min)continue;x2=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.min}if(y1>=y2&&y1>axisy.max){if(y2>axisy.max)continue;x1=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.max}else if(y2>=y1&&y2>axisy.max){if(y1>axisy.max)continue;x2=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.max}if(x1<=x2&&x1<axisx.min){if(x2<axisx.min)continue;y1=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.min}else if(x2<=x1&&x2<axisx.min){if(x1<axisx.min)continue;y2=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.min}if(x1>=x2&&x1>axisx.max){if(x2>axisx.max)continue;y1=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.max}else if(x2>=x1&&x2>axisx.max){if(x1>axisx.max)continue;y2=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.max}if(x1!=prevx||y1!=prevy)ctx.moveTo(axisx.p2c(x1)+xoffset,axisy.p2c(y1)+yoffset);prevx=x2;prevy=y2;ctx.lineTo(axisx.p2c(x2)+xoffset,axisy.p2c(y2)+yoffset)}ctx.stroke()}function plotLineArea(datapoints,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize,bottom=Math.min(Math.max(0,axisy.min),axisy.max),i=0,top,areaOpen=false,ypos=1,segmentStart=0,segmentEnd=0;while(true){if(ps>0&&i>points.length+ps)break;i+=ps;var x1=points[i-ps],y1=points[i-ps+ypos],x2=points[i],y2=points[i+ypos];if(areaOpen){if(ps>0&&x1!=null&&x2==null){segmentEnd=i;ps=-ps;ypos=2;continue}if(ps<0&&i==segmentStart+ps){ctx.fill();areaOpen=false;ps=-ps;ypos=1;i=segmentStart=segmentEnd+ps;continue}}if(x1==null||x2==null)continue;if(x1<=x2&&x1<axisx.min){if(x2<axisx.min)continue;y1=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.min}else if(x2<=x1&&x2<axisx.min){if(x1<axisx.min)continue;y2=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.min}if(x1>=x2&&x1>axisx.max){if(x2>axisx.max)continue;y1=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.max}else if(x2>=x1&&x2>axisx.max){if(x1>axisx.max)continue;y2=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.max}if(!areaOpen){ctx.beginPath();ctx.moveTo(axisx.p2c(x1),axisy.p2c(bottom));areaOpen=true}if(y1>=axisy.max&&y2>=axisy.max){ctx.lineTo(axisx.p2c(x1),axisy.p2c(axisy.max));ctx.lineTo(axisx.p2c(x2),axisy.p2c(axisy.max));continue}else if(y1<=axisy.min&&y2<=axisy.min){ctx.lineTo(axisx.p2c(x1),axisy.p2c(axisy.min));ctx.lineTo(axisx.p2c(x2),axisy.p2c(axisy.min));continue}var x1old=x1,x2old=x2;if(y1<=y2&&y1<axisy.min&&y2>=axisy.min){x1=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.min}else if(y2<=y1&&y2<axisy.min&&y1>=axisy.min){x2=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.min}if(y1>=y2&&y1>axisy.max&&y2<=axisy.max){x1=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.max}else if(y2>=y1&&y2>axisy.max&&y1<=axisy.max){x2=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.max}if(x1!=x1old){ctx.lineTo(axisx.p2c(x1old),axisy.p2c(y1))}ctx.lineTo(axisx.p2c(x1),axisy.p2c(y1));ctx.lineTo(axisx.p2c(x2),axisy.p2c(y2));if(x2!=x2old){ctx.lineTo(axisx.p2c(x2),axisy.p2c(y2));ctx.lineTo(axisx.p2c(x2old),axisy.p2c(y2))}}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.lineJoin="round";var lw=series.lines.lineWidth,sw=series.shadowSize;if(lw>0&&sw>0){ctx.lineWidth=sw;ctx.strokeStyle="rgba(0,0,0,0.1)";var angle=Math.PI/18;plotLine(series.datapoints,Math.sin(angle)*(lw/2+sw/2),Math.cos(angle)*(lw/2+sw/2),series.xaxis,series.yaxis);ctx.lineWidth=sw/2;plotLine(series.datapoints,Math.sin(angle)*(lw/2+sw/4),Math.cos(angle)*(lw/2+sw/4),series.xaxis,series.yaxis)}ctx.lineWidth=lw;ctx.strokeStyle=series.color;var fillStyle=getFillStyle(series.lines,series.color,0,plotHeight);if(fillStyle){ctx.fillStyle=fillStyle;plotLineArea(series.datapoints,series.xaxis,series.yaxis)}if(lw>0)plotLine(series.datapoints,0,0,series.xaxis,series.yaxis);ctx.restore()}function drawSeriesPoints(series){function plotPoints(datapoints,radius,fillStyle,offset,shadow,axisx,axisy,symbol){var points=datapoints.points,ps=datapoints.pointsize;for(var i=0;i<points.length;i+=ps){var x=points[i],y=points[i+1];if(x==null||x<axisx.min||x>axisx.max||y<axisy.min||y>axisy.max)continue;ctx.beginPath();x=axisx.p2c(x);y=axisy.p2c(y)+offset;if(symbol=="circle")ctx.arc(x,y,radius,0,shadow?Math.PI:Math.PI*2,false);else symbol(ctx,x,y,radius,shadow);ctx.closePath();if(fillStyle){ctx.fillStyle=fillStyle;ctx.fill()}ctx.stroke()}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var lw=series.points.lineWidth,sw=series.shadowSize,radius=series.points.radius,symbol=series.points.symbol;if(lw==0)lw=1e-4;if(lw>0&&sw>0){var w=sw/2;ctx.lineWidth=w;ctx.strokeStyle="rgba(0,0,0,0.1)";plotPoints(series.datapoints,radius,null,w+w/2,true,series.xaxis,series.yaxis,symbol);ctx.strokeStyle="rgba(0,0,0,0.2)";plotPoints(series.datapoints,radius,null,w/2,true,series.xaxis,series.yaxis,symbol)}ctx.lineWidth=lw;ctx.strokeStyle=series.color;plotPoints(series.datapoints,radius,getFillStyle(series.points,series.color),0,false,series.xaxis,series.yaxis,symbol);ctx.restore()}function drawBar(x,y,b,barLeft,barRight,fillStyleCallback,axisx,axisy,c,horizontal,lineWidth){var left,right,bottom,top,drawLeft,drawRight,drawTop,drawBottom,tmp;if(horizontal){drawBottom=drawRight=drawTop=true;drawLeft=false;left=b;right=x;top=y+barLeft;bottom=y+barRight;if(right<left){tmp=right;right=left;left=tmp;drawLeft=true;drawRight=false}}else{drawLeft=drawRight=drawTop=true;drawBottom=false;left=x+barLeft;right=x+barRight;bottom=b;top=y;if(top<bottom){tmp=top;top=bottom;bottom=tmp;drawBottom=true;drawTop=false}}if(right<axisx.min||left>axisx.max||top<axisy.min||bottom>axisy.max)return;if(left<axisx.min){left=axisx.min;drawLeft=false}if(right>axisx.max){right=axisx.max;drawRight=false}if(bottom<axisy.min){bottom=axisy.min;drawBottom=false}if(top>axisy.max){top=axisy.max;drawTop=false}left=axisx.p2c(left);bottom=axisy.p2c(bottom);right=axisx.p2c(right);top=axisy.p2c(top);if(fillStyleCallback){c.fillStyle=fillStyleCallback(bottom,top);c.fillRect(left,top,right-left,bottom-top)}if(lineWidth>0&&(drawLeft||drawRight||drawTop||drawBottom)){c.beginPath();c.moveTo(left,bottom);if(drawLeft)c.lineTo(left,top);else c.moveTo(left,top);if(drawTop)c.lineTo(right,top);else c.moveTo(right,top);if(drawRight)c.lineTo(right,bottom);else c.moveTo(right,bottom);if(drawBottom)c.lineTo(left,bottom);else c.moveTo(left,bottom);c.stroke()}}function drawSeriesBars(series){function plotBars(datapoints,barLeft,barRight,fillStyleCallback,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize;for(var i=0;i<points.length;i+=ps){if(points[i]==null)continue;drawBar(points[i],points[i+1],points[i+2],barLeft,barRight,fillStyleCallback,axisx,axisy,ctx,series.bars.horizontal,series.bars.lineWidth)}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.lineWidth=series.bars.lineWidth;ctx.strokeStyle=series.color;var barLeft;switch(series.bars.align){case"left":barLeft=0;break;case"right":barLeft=-series.bars.barWidth;break;default:barLeft=-series.bars.barWidth/2}var fillStyleCallback=series.bars.fill?function(bottom,top){return getFillStyle(series.bars,series.color,bottom,top)}:null;plotBars(series.datapoints,barLeft,barLeft+series.bars.barWidth,fillStyleCallback,series.xaxis,series.yaxis);ctx.restore()}function getFillStyle(filloptions,seriesColor,bottom,top){var fill=filloptions.fill;if(!fill)return null;if(filloptions.fillColor)return getColorOrGradient(filloptions.fillColor,bottom,top,seriesColor);var c=$.color.parse(seriesColor);c.a=typeof fill=="number"?fill:.4;c.normalize();return c.toString()}function insertLegend(){if(options.legend.container!=null){$(options.legend.container).html("")}else{placeholder.find(".legend").remove()}if(!options.legend.show){return}var fragments=[],entries=[],rowStarted=false,lf=options.legend.labelFormatter,s,label;for(var i=0;i<series.length;++i){s=series[i];if(s.label){label=lf?lf(s.label,s):s.label;if(label){entries.push({label:label,color:s.color})}}}if(options.legend.sorted){if($.isFunction(options.legend.sorted)){entries.sort(options.legend.sorted)}else if(options.legend.sorted=="reverse"){entries.reverse()}else{var ascending=options.legend.sorted!="descending";entries.sort(function(a,b){return a.label==b.label?0:a.label<b.label!=ascending?1:-1})}}for(var i=0;i<entries.length;++i){var entry=entries[i];if(i%options.legend.noColumns==0){if(rowStarted)fragments.push("</tr>");fragments.push("<tr>");rowStarted=true}fragments.push('<td class="legendColorBox"><div style="border:1px solid '+options.legend.labelBoxBorderColor+';padding:1px"><div style="width:4px;height:0;border:5px solid '+entry.color+';overflow:hidden"></div></div></td>'+'<td class="legendLabel">'+entry.label+"</td>")}if(rowStarted)fragments.push("</tr>");if(fragments.length==0)return;var table='<table style="font-size:smaller;color:'+options.grid.color+'">'+fragments.join("")+"</table>";if(options.legend.container!=null)$(options.legend.container).html(table);else{var pos="",p=options.legend.position,m=options.legend.margin;if(m[0]==null)m=[m,m];if(p.charAt(0)=="n")pos+="top:"+(m[1]+plotOffset.top)+"px;";else if(p.charAt(0)=="s")pos+="bottom:"+(m[1]+plotOffset.bottom)+"px;";if(p.charAt(1)=="e")pos+="right:"+(m[0]+plotOffset.right)+"px;";else if(p.charAt(1)=="w")pos+="left:"+(m[0]+plotOffset.left)+"px;";var legend=$('<div class="legend">'+table.replace('style="','style="position:absolute;'+pos+";")+"</div>").appendTo(placeholder);if(options.legend.backgroundOpacity!=0){var c=options.legend.backgroundColor;if(c==null){c=options.grid.backgroundColor;if(c&&typeof c=="string")c=$.color.parse(c);else c=$.color.extract(legend,"background-color");c.a=1;c=c.toString()}var div=legend.children();$('<div style="position:absolute;width:'+div.width()+"px;height:"+div.height()+"px;"+pos+"background-color:"+c+';"> </div>').prependTo(legend).css("opacity",options.legend.backgroundOpacity)}}}var highlights=[],redrawTimeout=null;function findNearbyItem(mouseX,mouseY,seriesFilter){var maxDistance=options.grid.mouseActiveRadius,smallestDistance=maxDistance*maxDistance+1,item=null,foundPoint=false,i,j,ps;for(i=series.length-1;i>=0;--i){if(!seriesFilter(series[i]))continue;var s=series[i],axisx=s.xaxis,axisy=s.yaxis,points=s.datapoints.points,mx=axisx.c2p(mouseX),my=axisy.c2p(mouseY),maxx=maxDistance/axisx.scale,maxy=maxDistance/axisy.scale;ps=s.datapoints.pointsize;if(axisx.options.inverseTransform)maxx=Number.MAX_VALUE;if(axisy.options.inverseTransform)maxy=Number.MAX_VALUE;if(s.lines.show||s.points.show){for(j=0;j<points.length;j+=ps){var x=points[j],y=points[j+1];if(x==null)continue;if(x-mx>maxx||x-mx<-maxx||y-my>maxy||y-my<-maxy)continue;var dx=Math.abs(axisx.p2c(x)-mouseX),dy=Math.abs(axisy.p2c(y)-mouseY),dist=dx*dx+dy*dy;if(dist<smallestDistance){smallestDistance=dist;item=[i,j/ps]}}}if(s.bars.show&&!item){var barLeft,barRight;switch(s.bars.align){case"left":barLeft=0;break;case"right":barLeft=-s.bars.barWidth;break;default:barLeft=-s.bars.barWidth/2}barRight=barLeft+s.bars.barWidth;for(j=0;j<points.length;j+=ps){var x=points[j],y=points[j+1],b=points[j+2];if(x==null)continue;if(series[i].bars.horizontal?mx<=Math.max(b,x)&&mx>=Math.min(b,x)&&my>=y+barLeft&&my<=y+barRight:mx>=x+barLeft&&mx<=x+barRight&&my>=Math.min(b,y)&&my<=Math.max(b,y))item=[i,j/ps]}}}if(item){i=item[0];j=item[1];ps=series[i].datapoints.pointsize;return{datapoint:series[i].datapoints.points.slice(j*ps,(j+1)*ps),dataIndex:j,series:series[i],seriesIndex:i}}return null}function onMouseMove(e){if(options.grid.hoverable)triggerClickHoverEvent("plothover",e,function(s){return s["hoverable"]!=false})}function onMouseLeave(e){if(options.grid.hoverable)triggerClickHoverEvent("plothover",e,function(s){return false})}function onClick(e){triggerClickHoverEvent("plotclick",e,function(s){return s["clickable"]!=false})}function triggerClickHoverEvent(eventname,event,seriesFilter){var offset=eventHolder.offset(),canvasX=event.pageX-offset.left-plotOffset.left,canvasY=event.pageY-offset.top-plotOffset.top,pos=canvasToAxisCoords({left:canvasX,top:canvasY});pos.pageX=event.pageX;pos.pageY=event.pageY;var item=findNearbyItem(canvasX,canvasY,seriesFilter);if(item){item.pageX=parseInt(item.series.xaxis.p2c(item.datapoint[0])+offset.left+plotOffset.left,10);item.pageY=parseInt(item.series.yaxis.p2c(item.datapoint[1])+offset.top+plotOffset.top,10)}if(options.grid.autoHighlight){for(var i=0;i<highlights.length;++i){var h=highlights[i];if(h.auto==eventname&&!(item&&h.series==item.series&&h.point[0]==item.datapoint[0]&&h.point[1]==item.datapoint[1]))unhighlight(h.series,h.point)}if(item)highlight(item.series,item.datapoint,eventname)}placeholder.trigger(eventname,[pos,item])}function triggerRedrawOverlay(){var t=options.interaction.redrawOverlayInterval;if(t==-1){drawOverlay();return}if(!redrawTimeout)redrawTimeout=setTimeout(drawOverlay,t)}function drawOverlay(){redrawTimeout=null;octx.save();overlay.clear();octx.translate(plotOffset.left,plotOffset.top);var i,hi;for(i=0;i<highlights.length;++i){hi=highlights[i];if(hi.series.bars.show)drawBarHighlight(hi.series,hi.point);else drawPointHighlight(hi.series,hi.point)}octx.restore();executeHooks(hooks.drawOverlay,[octx])}function highlight(s,point,auto){if(typeof s=="number")s=series[s];if(typeof point=="number"){var ps=s.datapoints.pointsize;point=s.datapoints.points.slice(ps*point,ps*(point+1))}var i=indexOfHighlight(s,point);if(i==-1){highlights.push({series:s,point:point,auto:auto});triggerRedrawOverlay()}else if(!auto)highlights[i].auto=false}function unhighlight(s,point){if(s==null&&point==null){highlights=[];triggerRedrawOverlay();return}if(typeof s=="number")s=series[s];if(typeof point=="number"){var ps=s.datapoints.pointsize;point=s.datapoints.points.slice(ps*point,ps*(point+1))}var i=indexOfHighlight(s,point);if(i!=-1){highlights.splice(i,1);triggerRedrawOverlay()}}function indexOfHighlight(s,p){for(var i=0;i<highlights.length;++i){var h=highlights[i];if(h.series==s&&h.point[0]==p[0]&&h.point[1]==p[1])return i}return-1}function drawPointHighlight(series,point){var x=point[0],y=point[1],axisx=series.xaxis,axisy=series.yaxis,highlightColor=typeof series.highlightColor==="string"?series.highlightColor:$.color.parse(series.color).scale("a",.5).toString();if(x<axisx.min||x>axisx.max||y<axisy.min||y>axisy.max)return;var pointRadius=series.points.radius+series.points.lineWidth/2;octx.lineWidth=pointRadius;octx.strokeStyle=highlightColor;var radius=1.5*pointRadius;x=axisx.p2c(x);y=axisy.p2c(y);octx.beginPath();if(series.points.symbol=="circle")octx.arc(x,y,radius,0,2*Math.PI,false);else series.points.symbol(octx,x,y,radius,false);octx.closePath();octx.stroke()}function drawBarHighlight(series,point){var highlightColor=typeof series.highlightColor==="string"?series.highlightColor:$.color.parse(series.color).scale("a",.5).toString(),fillStyle=highlightColor,barLeft;switch(series.bars.align){case"left":barLeft=0;break;case"right":barLeft=-series.bars.barWidth;break;default:barLeft=-series.bars.barWidth/2}octx.lineWidth=series.bars.lineWidth;octx.strokeStyle=highlightColor;drawBar(point[0],point[1],point[2]||0,barLeft,barLeft+series.bars.barWidth,function(){return fillStyle},series.xaxis,series.yaxis,octx,series.bars.horizontal,series.bars.lineWidth)}function getColorOrGradient(spec,bottom,top,defaultColor){if(typeof spec=="string")return spec;else{var gradient=ctx.createLinearGradient(0,top,0,bottom);for(var i=0,l=spec.colors.length;i<l;++i){var c=spec.colors[i];if(typeof c!="string"){var co=$.color.parse(defaultColor);if(c.brightness!=null)co=co.scale("rgb",c.brightness);if(c.opacity!=null)co.a*=c.opacity;c=co.toString()}gradient.addColorStop(i/(l-1),c)}return gradient}}}$.plot=function(placeholder,data,options){var plot=new Plot($(placeholder),data,options,$.plot.plugins);return plot};$.plot.version="0.8.3";$.plot.plugins=[];$.fn.plot=function(data,options){return this.each(function(){$.plot(this,data,options)})};function floorInBase(n,base){return base*Math.floor(n/base)}})(jQuery);
\ No newline at end of file
diff --git a/htdocs/Libs/Flot/jquery.flot.navigate.min.js b/htdocs/Libs/Flot/jquery.flot.navigate.min.js
new file mode 100644
index 0000000..f9ce65d
--- /dev/null
+++ b/htdocs/Libs/Flot/jquery.flot.navigate.min.js
@@ -0,0 +1,7 @@
+/* Javascript plotting library for jQuery, version 0.8.3.
+
+Copyright (c) 2007-2014 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+*/
+!function(e){function t(a){var g,d=this,l=a.data||{};if(l.elem)d=a.dragTarget=l.elem,a.dragProxy=u.proxy||d,a.cursorOffsetX=l.pageX-l.left,a.cursorOffsetY=l.pageY-l.top,a.offsetX=a.pageX-a.cursorOffsetX,a.offsetY=a.pageY-a.cursorOffsetY;else if(u.dragging||l.which>0&&a.which!=l.which||e(a.target).is(l.not))return;switch(a.type){case"mousedown":return e.extend(l,e(d).offset(),{elem:d,target:a.target,pageX:a.pageX,pageY:a.pageY}),i.add(document,"mousemove mouseup",t,l),r(d,!1),u.dragging=null,!1;case!u.dragging&&"mousemove":if(o(a.pageX-l.pageX)+o(a.pageY-l.pageY)<l.distance)break;a.target=l.target,g=n(a,"dragstart",d),g!==!1&&(u.dragging=d,u.proxy=a.dragProxy=e(g||d)[0]);case"mousemove":if(u.dragging){if(g=n(a,"drag",d),s.drop&&(s.drop.allowed=g!==!1,s.drop.handler(a)),g!==!1)break;a.type="mouseup"}case"mouseup":i.remove(document,"mousemove mouseup",t),u.dragging&&(s.drop&&s.drop.handler(a),n(a,"dragend",d)),r(d,!0),u.dragging=u.proxy=l.elem=!1}return!0}function n(t,n,o){t.type=n;var a=e.event.dispatch.call(o,t);return a===!1?!1:a||t.result}function o(e){return Math.pow(e,2)}function a(){return u.dragging===!1}function r(e,t){e&&(e.unselectable=t?"off":"on",e.onselectstart=function(){return t},e.style&&(e.style.MozUserSelect=t?"":"none"))}e.fn.drag=function(e,t,n){return t&&this.bind("dragstart",e),n&&this.bind("dragend",n),e?this.bind("drag",t?t:e):this.trigger("drag")};var i=e.event,s=i.special,u=s.drag={not:":input",distance:0,which:1,dragging:!1,setup:function(n){n=e.extend({distance:u.distance,which:u.which,not:u.not},n||{}),n.distance=o(n.distance),i.add(this,"mousedown",t,n),this.attachEvent&&this.attachEvent("ondragstart",a)},teardown:function(){i.remove(this,"mousedown",t),this===u.dragging&&(u.dragging=u.proxy=!1),r(this,!0),this.detachEvent&&this.detachEvent("ondragstart",a)}};s.dragstart=s.dragend={setup:function(){},teardown:function(){}}}(jQuery),function(e){function t(t){var n=t||window.event,o=[].slice.call(arguments,1),a=0,r=0,i=0,t=e.event.fix(n);return t.type="mousewheel",n.wheelDelta&&(a=n.wheelDelta/120),n.detail&&(a=-n.detail/3),i=a,void 0!==n.axis&&n.axis===n.HORIZONTAL_AXIS&&(i=0,r=-1*a),void 0!==n.wheelDeltaY&&(i=n.wheelDeltaY/120),void 0!==n.wheelDeltaX&&(r=-1*n.wheelDeltaX/120),o.unshift(t,a,r,i),(e.event.dispatch||e.event.handle).apply(this,o)}var n=["DOMMouseScroll","mousewheel"];if(e.event.fixHooks)for(var o=n.length;o;)e.event.fixHooks[n[--o]]=e.event.mouseHooks;e.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var e=n.length;e;)this.addEventListener(n[--e],t,!1);else this.onmousewheel=t},teardown:function(){if(this.removeEventListener)for(var e=n.length;e;)this.removeEventListener(n[--e],t,!1);else this.onmousewheel=null}},e.fn.extend({mousewheel:function(e){return e?this.bind("mousewheel",e):this.trigger("mousewheel")},unmousewheel:function(e){return this.unbind("mousewheel",e)}})}(jQuery),function(e){function t(t){function n(e,n){var o=t.offset();o.left=e.pageX-o.left,o.top=e.pageY-o.top,n?t.zoomOut({center:o}):t.zoom({center:o})}function o(e,t){return e.preventDefault(),n(e,0>t),!1}function a(e){if(1!=e.which)return!1;var n=t.getPlaceholder().css("cursor");n&&(g=n),t.getPlaceholder().css("cursor",t.getOptions().pan.cursor),d=e.pageX,l=e.pageY}function r(e){var n=t.getOptions().pan.frameRate;!c&&n&&(c=setTimeout(function(){t.pan({left:d-e.pageX,top:l-e.pageY}),d=e.pageX,l=e.pageY,c=null},1/n*1e3))}function i(e){c&&(clearTimeout(c),c=null),t.getPlaceholder().css("cursor",g),t.pan({left:d-e.pageX,top:l-e.pageY})}function s(e,t){var s=e.getOptions();s.zoom.interactive&&(t[s.zoom.trigger](n),t.mousewheel(o)),s.pan.interactive&&(t.bind("dragstart",{distance:10},a),t.bind("drag",r),t.bind("dragend",i))}function u(e,t){t.unbind(e.getOptions().zoom.trigger,n),t.unbind("mousewheel",o),t.unbind("dragstart",a),t.unbind("drag",r),t.unbind("dragend",i),c&&clearTimeout(c)}var g="default",d=0,l=0,c=null;t.zoomOut=function(e){e||(e={}),e.amount||(e.amount=t.getOptions().zoom.amount),e.amount=1/e.amount,t.zoom(e)},t.zoom=function(n){n||(n={});var o=n.center,a=n.amount||t.getOptions().zoom.amount,r=t.width(),i=t.height();o||(o={left:r/2,top:i/2});var s=o.left/r,u=o.top/i,g={x:{min:o.left-s*r/a,max:o.left+(1-s)*r/a},y:{min:o.top-u*i/a,max:o.top+(1-u)*i/a}};e.each(t.getAxes(),function(e,t){var n=t.options,o=g[t.direction].min,r=g[t.direction].max,i=n.zoomRange,s=n.panRange;if(i!==!1){if(o=t.c2p(o),r=t.c2p(r),o>r){var u=o;o=r,r=u}s&&(null!=s[0]&&o<s[0]&&(o=s[0]),null!=s[1]&&r>s[1]&&(r=s[1]));var d=r-o;i&&(null!=i[0]&&d<i[0]&&a>1||null!=i[1]&&d>i[1]&&1>a)||(n.min=o,n.max=r)}}),t.setupGrid(),t.draw(),n.preventEvent||t.getPlaceholder().trigger("plotzoom",[t,n])},t.pan=function(n){var o={x:+n.left,y:+n.top};isNaN(o.x)&&(o.x=0),isNaN(o.y)&&(o.y=0),e.each(t.getAxes(),function(e,t){var n,a,r=t.options,i=o[t.direction];n=t.c2p(t.p2c(t.min)+i),a=t.c2p(t.p2c(t.max)+i);var s=r.panRange;s!==!1&&(s&&(null!=s[0]&&s[0]>n&&(i=s[0]-n,n+=i,a+=i),null!=s[1]&&s[1]<a&&(i=s[1]-a,n+=i,a+=i)),r.min=n,r.max=a)}),t.setupGrid(),t.draw(),n.preventEvent||t.getPlaceholder().trigger("plotpan",[t,n])},t.hooks.bindEvents.push(s),t.hooks.shutdown.push(u)}var n={xaxis:{zoomRange:null,panRange:null},zoom:{interactive:!1,trigger:"dblclick",amount:1.5},pan:{interactive:!1,cursor:"move",frameRate:20}};e.plot.plugins.push({init:t,options:n,name:"navigate",version:"1.3"})}(jQuery);
\ No newline at end of file
diff --git a/htdocs/Libs/Flot/jquery.flot.resize.min.js b/htdocs/Libs/Flot/jquery.flot.resize.min.js
new file mode 100644
index 0000000..a4fb5be
--- /dev/null
+++ b/htdocs/Libs/Flot/jquery.flot.resize.min.js
@@ -0,0 +1,7 @@
+/* Javascript plotting library for jQuery, version 0.8.3.

+

+Copyright (c) 2007-2014 IOLA and Ole Laursen.

+Licensed under the MIT license.

+

+*/

+(function($,e,t){"$:nomunge";var i=[],n=$.resize=$.extend($.resize,{}),a,r=false,s="setTimeout",u="resize",m=u+"-special-event",o="pendingDelay",l="activeDelay",f="throttleWindow";n[o]=200;n[l]=20;n[f]=true;$.event.special[u]={setup:function(){if(!n[f]&&this[s]){return false}var e=$(this);i.push(this);e.data(m,{w:e.width(),h:e.height()});if(i.length===1){a=t;h()}},teardown:function(){if(!n[f]&&this[s]){return false}var e=$(this);for(var t=i.length-1;t>=0;t--){if(i[t]==this){i.splice(t,1);break}}e.removeData(m);if(!i.length){if(r){cancelAnimationFrame(a)}else{clearTimeout(a)}a=null}},add:function(e){if(!n[f]&&this[s]){return false}var i;function a(e,n,a){var r=$(this),s=r.data(m)||{};s.w=n!==t?n:r.width();s.h=a!==t?a:r.height();i.apply(this,arguments)}if($.isFunction(e)){i=e;return a}else{i=e.handler;e.handler=a}}};function h(t){if(r===true){r=t||1}for(var s=i.length-1;s>=0;s--){var l=$(i[s]);if(l[0]==e||l.is(":visible")){var f=l.width(),c=l.height(),d=l.data(m);if(d&&(f!==d.w||c!==d.h)){l.trigger(u,[d.w=f,d.h=c]);r=t||true}}else{d=l.data(m);d.w=0;d.h=0}}if(a!==null){if(r&&(t==null||t-r<1e3)){a=e.requestAnimationFrame(h)}else{a=setTimeout(h,n[o]);r=false}}}if(!e.requestAnimationFrame){e.requestAnimationFrame=function(){return e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(t,i){return e.setTimeout(function(){t((new Date).getTime())},n[l])}}()}if(!e.cancelAnimationFrame){e.cancelAnimationFrame=function(){return e.webkitCancelRequestAnimationFrame||e.mozCancelRequestAnimationFrame||e.oCancelRequestAnimationFrame||e.msCancelRequestAnimationFrame||clearTimeout}()}})(jQuery,this);(function($){var options={};function init(plot){function onResize(){var placeholder=plot.getPlaceholder();if(placeholder.width()==0||placeholder.height()==0)return;plot.resize();plot.setupGrid();plot.draw()}function bindEvents(plot,eventHolder){plot.getPlaceholder().resize(onResize)}function shutdown(plot,eventHolder){plot.getPlaceholder().unbind("resize",onResize)}plot.hooks.bindEvents.push(bindEvents);plot.hooks.shutdown.push(shutdown)}$.plot.plugins.push({init:init,options:options,name:"resize",version:"1.0"})})(jQuery);
\ No newline at end of file
diff --git a/htdocs/Libs/Flot/jquery.flot.time.js b/htdocs/Libs/Flot/jquery.flot.time.js
new file mode 100644
index 0000000..34c1d12
--- /dev/null
+++ b/htdocs/Libs/Flot/jquery.flot.time.js
@@ -0,0 +1,432 @@
+/* Pretty handling of time axes.
+
+Copyright (c) 2007-2014 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+Set axis.mode to "time" to enable. See the section "Time series data" in
+API.txt for details.
+
+*/
+
+(function($) {
+
+	var options = {
+		xaxis: {
+			timezone: null,		// "browser" for local to the client or timezone for timezone-js
+			timeformat: null,	// format string to use
+			twelveHourClock: false,	// 12 or 24 time in time mode
+			monthNames: null	// list of names of months
+		}
+	};
+
+	// round to nearby lower multiple of base
+
+	function floorInBase(n, base) {
+		return base * Math.floor(n / base);
+	}
+
+	// Returns a string with the date d formatted according to fmt.
+	// A subset of the Open Group's strftime format is supported.
+
+	function formatDate(d, fmt, monthNames, dayNames) {
+
+		if (typeof d.strftime == "function") {
+			return d.strftime(fmt);
+		}
+
+		var leftPad = function(n, pad) {
+			n = "" + n;
+			pad = "" + (pad == null ? "0" : pad);
+			return n.length == 1 ? pad + n : n;
+		};
+
+		var r = [];
+		var escape = false;
+		var hours = d.getHours();
+		var isAM = hours < 12;
+
+		if (monthNames == null) {
+			monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
+		}
+
+		if (dayNames == null) {
+			dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
+		}
+
+		var hours12;
+
+		if (hours > 12) {
+			hours12 = hours - 12;
+		} else if (hours == 0) {
+			hours12 = 12;
+		} else {
+			hours12 = hours;
+		}
+
+		for (var i = 0; i < fmt.length; ++i) {
+
+			var c = fmt.charAt(i);
+
+			if (escape) {
+				switch (c) {
+					case 'a': c = "" + dayNames[d.getDay()]; break;
+					case 'b': c = "" + monthNames[d.getMonth()]; break;
+					case 'd': c = leftPad(d.getDate()); break;
+					case 'e': c = leftPad(d.getDate(), " "); break;
+					case 'h':	// For back-compat with 0.7; remove in 1.0
+					case 'H': c = leftPad(hours); break;
+					case 'I': c = leftPad(hours12); break;
+					case 'l': c = leftPad(hours12, " "); break;
+					case 'm': c = leftPad(d.getMonth() + 1); break;
+					case 'M': c = leftPad(d.getMinutes()); break;
+					// quarters not in Open Group's strftime specification
+					case 'q':
+						c = "" + (Math.floor(d.getMonth() / 3) + 1); break;
+					case 'S': c = leftPad(d.getSeconds()); break;
+					case 'y': c = leftPad(d.getFullYear() % 100); break;
+					case 'Y': c = "" + d.getFullYear(); break;
+					case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break;
+					case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break;
+					case 'w': c = "" + d.getDay(); break;
+				}
+				r.push(c);
+				escape = false;
+			} else {
+				if (c == "%") {
+					escape = true;
+				} else {
+					r.push(c);
+				}
+			}
+		}
+
+		return r.join("");
+	}
+
+	// To have a consistent view of time-based data independent of which time
+	// zone the client happens to be in we need a date-like object independent
+	// of time zones.  This is done through a wrapper that only calls the UTC
+	// versions of the accessor methods.
+
+	function makeUtcWrapper(d) {
+
+		function addProxyMethod(sourceObj, sourceMethod, targetObj, targetMethod) {
+			sourceObj[sourceMethod] = function() {
+				return targetObj[targetMethod].apply(targetObj, arguments);
+			};
+		};
+
+		var utc = {
+			date: d
+		};
+
+		// support strftime, if found
+
+		if (d.strftime != undefined) {
+			addProxyMethod(utc, "strftime", d, "strftime");
+		}
+
+		addProxyMethod(utc, "getTime", d, "getTime");
+		addProxyMethod(utc, "setTime", d, "setTime");
+
+		var props = ["Date", "Day", "FullYear", "Hours", "Milliseconds", "Minutes", "Month", "Seconds"];
+
+		for (var p = 0; p < props.length; p++) {
+			addProxyMethod(utc, "get" + props[p], d, "getUTC" + props[p]);
+			addProxyMethod(utc, "set" + props[p], d, "setUTC" + props[p]);
+		}
+
+		return utc;
+	};
+
+	// select time zone strategy.  This returns a date-like object tied to the
+	// desired timezone
+
+	function dateGenerator(ts, opts) {
+		if (opts.timezone == "browser") {
+			return new Date(ts);
+		} else if (!opts.timezone || opts.timezone == "utc") {
+			return makeUtcWrapper(new Date(ts));
+		} else if (typeof timezoneJS != "undefined" && typeof timezoneJS.Date != "undefined") {
+			var d = new timezoneJS.Date();
+			// timezone-js is fickle, so be sure to set the time zone before
+			// setting the time.
+			d.setTimezone(opts.timezone);
+			d.setTime(ts);
+			return d;
+		} else {
+			return makeUtcWrapper(new Date(ts));
+		}
+	}
+	
+	// map of app. size of time units in milliseconds
+
+	var timeUnitSize = {
+		"second": 1000,
+		"minute": 60 * 1000,
+		"hour": 60 * 60 * 1000,
+		"day": 24 * 60 * 60 * 1000,
+		"month": 30 * 24 * 60 * 60 * 1000,
+		"quarter": 3 * 30 * 24 * 60 * 60 * 1000,
+		"year": 365.2425 * 24 * 60 * 60 * 1000
+	};
+
+	// the allowed tick sizes, after 1 year we use
+	// an integer algorithm
+
+	var baseSpec = [
+		[1, "second"], [2, "second"], [5, "second"], [10, "second"],
+		[30, "second"], 
+		[1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"],
+		[30, "minute"], 
+		[1, "hour"], [2, "hour"], [4, "hour"],
+		[8, "hour"], [12, "hour"],
+		[1, "day"], [2, "day"], [3, "day"],
+		[0.25, "month"], [0.5, "month"], [1, "month"],
+		[2, "month"]
+	];
+
+	// we don't know which variant(s) we'll need yet, but generating both is
+	// cheap
+
+	var specMonths = baseSpec.concat([[3, "month"], [6, "month"],
+		[1, "year"]]);
+	var specQuarters = baseSpec.concat([[1, "quarter"], [2, "quarter"],
+		[1, "year"]]);
+
+	function init(plot) {
+		plot.hooks.processOptions.push(function (plot, options) {
+			$.each(plot.getAxes(), function(axisName, axis) {
+
+				var opts = axis.options;
+
+				if (opts.mode == "time") {
+					axis.tickGenerator = function(axis) {
+
+						var ticks = [];
+						var d = dateGenerator(axis.min, opts);
+						var minSize = 0;
+
+						// make quarter use a possibility if quarters are
+						// mentioned in either of these options
+
+						var spec = (opts.tickSize && opts.tickSize[1] ===
+							"quarter") ||
+							(opts.minTickSize && opts.minTickSize[1] ===
+							"quarter") ? specQuarters : specMonths;
+
+						if (opts.minTickSize != null) {
+							if (typeof opts.tickSize == "number") {
+								minSize = opts.tickSize;
+							} else {
+								minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]];
+							}
+						}
+
+						for (var i = 0; i < spec.length - 1; ++i) {
+							if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]]
+											  + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2
+								&& spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) {
+								break;
+							}
+						}
+
+						var size = spec[i][0];
+						var unit = spec[i][1];
+
+						// special-case the possibility of several years
+
+						if (unit == "year") {
+
+							// if given a minTickSize in years, just use it,
+							// ensuring that it's an integer
+
+							if (opts.minTickSize != null && opts.minTickSize[1] == "year") {
+								size = Math.floor(opts.minTickSize[0]);
+							} else {
+
+								var magn = Math.pow(10, Math.floor(Math.log(axis.delta / timeUnitSize.year) / Math.LN10));
+								var norm = (axis.delta / timeUnitSize.year) / magn;
+
+								if (norm < 1.5) {
+									size = 1;
+								} else if (norm < 3) {
+									size = 2;
+								} else if (norm < 7.5) {
+									size = 5;
+								} else {
+									size = 10;
+								}
+
+								size *= magn;
+							}
+
+							// minimum size for years is 1
+
+							if (size < 1) {
+								size = 1;
+							}
+						}
+
+						axis.tickSize = opts.tickSize || [size, unit];
+						var tickSize = axis.tickSize[0];
+						unit = axis.tickSize[1];
+
+						var step = tickSize * timeUnitSize[unit];
+
+						if (unit == "second") {
+							d.setSeconds(floorInBase(d.getSeconds(), tickSize));
+						} else if (unit == "minute") {
+							d.setMinutes(floorInBase(d.getMinutes(), tickSize));
+						} else if (unit == "hour") {
+							d.setHours(floorInBase(d.getHours(), tickSize));
+						} else if (unit == "month") {
+							d.setMonth(floorInBase(d.getMonth(), tickSize));
+						} else if (unit == "quarter") {
+							d.setMonth(3 * floorInBase(d.getMonth() / 3,
+								tickSize));
+						} else if (unit == "year") {
+							d.setFullYear(floorInBase(d.getFullYear(), tickSize));
+						}
+
+						// reset smaller components
+
+						d.setMilliseconds(0);
+
+						if (step >= timeUnitSize.minute) {
+							d.setSeconds(0);
+						}
+						if (step >= timeUnitSize.hour) {
+							d.setMinutes(0);
+						}
+						if (step >= timeUnitSize.day) {
+							d.setHours(0);
+						}
+						if (step >= timeUnitSize.day * 4) {
+							d.setDate(1);
+						}
+						if (step >= timeUnitSize.month * 2) {
+							d.setMonth(floorInBase(d.getMonth(), 3));
+						}
+						if (step >= timeUnitSize.quarter * 2) {
+							d.setMonth(floorInBase(d.getMonth(), 6));
+						}
+						if (step >= timeUnitSize.year) {
+							d.setMonth(0);
+						}
+
+						var carry = 0;
+						var v = Number.NaN;
+						var prev;
+
+						do {
+
+							prev = v;
+							v = d.getTime();
+							ticks.push(v);
+
+							if (unit == "month" || unit == "quarter") {
+								if (tickSize < 1) {
+
+									// a bit complicated - we'll divide the
+									// month/quarter up but we need to take
+									// care of fractions so we don't end up in
+									// the middle of a day
+
+									d.setDate(1);
+									var start = d.getTime();
+									d.setMonth(d.getMonth() +
+										(unit == "quarter" ? 3 : 1));
+									var end = d.getTime();
+									d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize);
+									carry = d.getHours();
+									d.setHours(0);
+								} else {
+									d.setMonth(d.getMonth() +
+										tickSize * (unit == "quarter" ? 3 : 1));
+								}
+							} else if (unit == "year") {
+								d.setFullYear(d.getFullYear() + tickSize);
+							} else {
+								d.setTime(v + step);
+							}
+						} while (v < axis.max && v != prev);
+
+						return ticks;
+					};
+
+					axis.tickFormatter = function (v, axis) {
+
+						var d = dateGenerator(v, axis.options);
+
+						// first check global format
+
+						if (opts.timeformat != null) {
+							return formatDate(d, opts.timeformat, opts.monthNames, opts.dayNames);
+						}
+
+						// possibly use quarters if quarters are mentioned in
+						// any of these places
+
+						var useQuarters = (axis.options.tickSize &&
+								axis.options.tickSize[1] == "quarter") ||
+							(axis.options.minTickSize &&
+								axis.options.minTickSize[1] == "quarter");
+
+						var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];
+						var span = axis.max - axis.min;
+						var suffix = (opts.twelveHourClock) ? " %p" : "";
+						var hourCode = (opts.twelveHourClock) ? "%I" : "%H";
+						var fmt;
+
+						if (t < timeUnitSize.minute) {
+							fmt = hourCode + ":%M:%S" + suffix;
+						} else if (t < timeUnitSize.day) {
+							if (span < 2 * timeUnitSize.day) {
+								fmt = hourCode + ":%M" + suffix;
+							} else {
+								fmt = "%b %d " + hourCode + ":%M" + suffix;
+							}
+						} else if (t < timeUnitSize.month) {
+							fmt = "%b %d";
+						} else if ((useQuarters && t < timeUnitSize.quarter) ||
+							(!useQuarters && t < timeUnitSize.year)) {
+							if (span < timeUnitSize.year) {
+								fmt = "%b";
+							} else {
+								fmt = "%b %Y";
+							}
+						} else if (useQuarters && t < timeUnitSize.year) {
+							if (span < timeUnitSize.year) {
+								fmt = "Q%q";
+							} else {
+								fmt = "Q%q %Y";
+							}
+						} else {
+							fmt = "%Y";
+						}
+
+						var rt = formatDate(d, fmt, opts.monthNames, opts.dayNames);
+
+						return rt;
+					};
+				}
+			});
+		});
+	}
+
+	$.plot.plugins.push({
+		init: init,
+		options: options,
+		name: 'time',
+		version: '1.0'
+	});
+
+	// Time-axis support used to be in Flot core, which exposed the
+	// formatDate function on the plot object.  Various plugins depend
+	// on the function, so we need to re-expose it here.
+
+	$.plot.formatDate = formatDate;
+	$.plot.dateGenerator = dateGenerator;
+
+})(jQuery);
diff --git a/htdocs/Libs/Html2Canvas/html2canvas.js b/htdocs/Libs/Html2Canvas/html2canvas.js
new file mode 100644
index 0000000..152316b
--- /dev/null
+++ b/htdocs/Libs/Html2Canvas/html2canvas.js
@@ -0,0 +1,2868 @@
+/*

+  html2canvas 0.4.1 <http://html2canvas.hertzen.com>

+  Copyright (c) 2013 Niklas von Hertzen

+

+  Released under MIT License

+*/

+

+(function(window, document, undefined){

+

+"use strict";

+

+var _html2canvas = {},

+previousElement,

+computedCSS,

+html2canvas;

+

+_html2canvas.Util = {};

+

+_html2canvas.Util.log = function(a) {

+  if (_html2canvas.logging && window.console && window.console.log) {

+    window.console.log(a);

+  }

+};

+

+_html2canvas.Util.trimText = (function(isNative){

+  return function(input) {

+    return isNative ? isNative.apply(input) : ((input || '') + '').replace( /^\s+|\s+$/g , '' );

+  };

+})(String.prototype.trim);

+

+_html2canvas.Util.asFloat = function(v) {

+  return parseFloat(v);

+};

+

+(function() {

+  // TODO: support all possible length values

+  var TEXT_SHADOW_PROPERTY = /((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g;

+  var TEXT_SHADOW_VALUES = /(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g;

+  _html2canvas.Util.parseTextShadows = function (value) {

+    if (!value || value === 'none') {

+      return [];

+    }

+

+    // find multiple shadow declarations

+    var shadows = value.match(TEXT_SHADOW_PROPERTY),

+      results = [];

+    for (var i = 0; shadows && (i < shadows.length); i++) {

+      var s = shadows[i].match(TEXT_SHADOW_VALUES);

+      results.push({

+        color: s[0],

+        offsetX: s[1] ? s[1].replace('px', '') : 0,

+        offsetY: s[2] ? s[2].replace('px', '') : 0,

+        blur: s[3] ? s[3].replace('px', '') : 0

+      });

+    }

+    return results;

+  };

+})();

+

+

+_html2canvas.Util.parseBackgroundImage = function (value) {

+    var whitespace = ' \r\n\t',

+        method, definition, prefix, prefix_i, block, results = [],

+        c, mode = 0, numParen = 0, quote, args;

+

+    var appendResult = function(){

+        if(method) {

+            if(definition.substr( 0, 1 ) === '"') {

+                definition = definition.substr( 1, definition.length - 2 );

+            }

+            if(definition) {

+                args.push(definition);

+            }

+            if(method.substr( 0, 1 ) === '-' &&

+                    (prefix_i = method.indexOf( '-', 1 ) + 1) > 0) {

+                prefix = method.substr( 0, prefix_i);

+                method = method.substr( prefix_i );

+            }

+            results.push({

+                prefix: prefix,

+                method: method.toLowerCase(),

+                value: block,

+                args: args

+            });

+        }

+        args = []; //for some odd reason, setting .length = 0 didn't work in safari

+        method =

+            prefix =

+            definition =

+            block = '';

+    };

+

+    appendResult();

+    for(var i = 0, ii = value.length; i<ii; i++) {

+        c = value[i];

+        if(mode === 0 && whitespace.indexOf( c ) > -1){

+            continue;

+        }

+        switch(c) {

+            case '"':

+                if(!quote) {

+                    quote = c;

+                }

+                else if(quote === c) {

+                    quote = null;

+                }

+                break;

+

+            case '(':

+                if(quote) { break; }

+                else if(mode === 0) {

+                    mode = 1;

+                    block += c;

+                    continue;

+                } else {

+                    numParen++;

+                }

+                break;

+

+            case ')':

+                if(quote) { break; }

+                else if(mode === 1) {

+                    if(numParen === 0) {

+                        mode = 0;

+                        block += c;

+                        appendResult();

+                        continue;

+                    } else {

+                        numParen--;

+                    }

+                }

+                break;

+

+            case ',':

+                if(quote) { break; }

+                else if(mode === 0) {

+                    appendResult();

+                    continue;

+                }

+                else if (mode === 1) {

+                    if(numParen === 0 && !method.match(/^url$/i)) {

+                        args.push(definition);

+                        definition = '';

+                        block += c;

+                        continue;

+                    }

+                }

+                break;

+        }

+

+        block += c;

+        if(mode === 0) { method += c; }

+        else { definition += c; }

+    }

+    appendResult();

+

+    return results;

+};

+

+_html2canvas.Util.Bounds = function (element) {

+  var clientRect, bounds = {};

+

+  if (element.getBoundingClientRect){

+    clientRect = element.getBoundingClientRect();

+

+    // TODO add scroll position to bounds, so no scrolling of window necessary

+    bounds.top = clientRect.top;

+    bounds.bottom = clientRect.bottom || (clientRect.top + clientRect.height);

+    bounds.left = clientRect.left;

+

+    bounds.width = element.offsetWidth;

+    bounds.height = element.offsetHeight;

+  }

+

+  return bounds;

+};

+

+// TODO ideally, we'd want everything to go through this function instead of Util.Bounds,

+// but would require further work to calculate the correct positions for elements with offsetParents

+_html2canvas.Util.OffsetBounds = function (element) {

+  var parent = element.offsetParent ? _html2canvas.Util.OffsetBounds(element.offsetParent) : {top: 0, left: 0};

+

+  return {

+    top: element.offsetTop + parent.top,

+    bottom: element.offsetTop + element.offsetHeight + parent.top,

+    left: element.offsetLeft + parent.left,

+    width: element.offsetWidth,

+    height: element.offsetHeight

+  };

+};

+

+function toPX(element, attribute, value ) {

+    var rsLeft = element.runtimeStyle && element.runtimeStyle[attribute],

+        left,

+        style = element.style;

+

+    // Check if we are not dealing with pixels, (Opera has issues with this)

+    // Ported from jQuery css.js

+    // From the awesome hack by Dean Edwards

+    // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291

+

+    // If we're not dealing with a regular pixel number

+    // but a number that has a weird ending, we need to convert it to pixels

+

+    if ( !/^-?[0-9]+\.?[0-9]*(?:px)?$/i.test( value ) && /^-?\d/.test(value) ) {

+        // Remember the original values

+        left = style.left;

+

+        // Put in the new values to get a computed value out

+        if (rsLeft) {

+            element.runtimeStyle.left = element.currentStyle.left;

+        }

+        style.left = attribute === "fontSize" ? "1em" : (value || 0);

+        value = style.pixelLeft + "px";

+

+        // Revert the changed values

+        style.left = left;

+        if (rsLeft) {

+            element.runtimeStyle.left = rsLeft;

+        }

+    }

+

+    if (!/^(thin|medium|thick)$/i.test(value)) {

+        return Math.round(parseFloat(value)) + "px";

+    }

+

+    return value;

+}

+

+function asInt(val) {

+    return parseInt(val, 10);

+}

+

+function parseBackgroundSizePosition(value, element, attribute, index) {

+    value = (value || '').split(',');

+    value = value[index || 0] || value[0] || 'auto';

+    value = _html2canvas.Util.trimText(value).split(' ');

+

+    if(attribute === 'backgroundSize' && (!value[0] || value[0].match(/cover|contain|auto/))) {

+        //these values will be handled in the parent function

+    } else {

+        value[0] = (value[0].indexOf( "%" ) === -1) ? toPX(element, attribute + "X", value[0]) : value[0];

+        if(value[1] === undefined) {

+            if(attribute === 'backgroundSize') {

+                value[1] = 'auto';

+                return value;

+            } else {

+                // IE 9 doesn't return double digit always

+                value[1] = value[0];

+            }

+        }

+        value[1] = (value[1].indexOf("%") === -1) ? toPX(element, attribute + "Y", value[1]) : value[1];

+    }

+    return value;

+}

+

+_html2canvas.Util.getCSS = function (element, attribute, index) {

+    if (previousElement !== element) {

+      computedCSS = document.defaultView.getComputedStyle(element, null);

+    }

+

+    var value = computedCSS[attribute];

+

+    if (/^background(Size|Position)$/.test(attribute)) {

+        return parseBackgroundSizePosition(value, element, attribute, index);

+    } else if (/border(Top|Bottom)(Left|Right)Radius/.test(attribute)) {

+      var arr = value.split(" ");

+      if (arr.length <= 1) {

+          arr[1] = arr[0];

+      }

+      return arr.map(asInt);

+    }

+

+  return value;

+};

+

+_html2canvas.Util.resizeBounds = function( current_width, current_height, target_width, target_height, stretch_mode ){

+  var target_ratio = target_width / target_height,

+    current_ratio = current_width / current_height,

+    output_width, output_height;

+

+  if(!stretch_mode || stretch_mode === 'auto') {

+    output_width = target_width;

+    output_height = target_height;

+  } else if(target_ratio < current_ratio ^ stretch_mode === 'contain') {

+    output_height = target_height;

+    output_width = target_height * current_ratio;

+  } else {

+    output_width = target_width;

+    output_height = target_width / current_ratio;

+  }

+

+  return {

+    width: output_width,

+    height: output_height

+  };

+};

+

+function backgroundBoundsFactory( prop, el, bounds, image, imageIndex, backgroundSize ) {

+    var bgposition =  _html2canvas.Util.getCSS( el, prop, imageIndex ) ,

+    topPos,

+    left,

+    percentage,

+    val;

+

+    if (bgposition.length === 1){

+      val = bgposition[0];

+

+      bgposition = [];

+

+      bgposition[0] = val;

+      bgposition[1] = val;

+    }

+

+    if (bgposition[0].toString().indexOf("%") !== -1){

+      percentage = (parseFloat(bgposition[0])/100);

+      left = bounds.width * percentage;

+      if(prop !== 'backgroundSize') {

+        left -= (backgroundSize || image).width*percentage;

+      }

+    } else {

+      if(prop === 'backgroundSize') {

+        if(bgposition[0] === 'auto') {

+          left = image.width;

+        } else {

+          if (/contain|cover/.test(bgposition[0])) {

+            var resized = _html2canvas.Util.resizeBounds(image.width, image.height, bounds.width, bounds.height, bgposition[0]);

+            left = resized.width;

+            topPos = resized.height;

+          } else {

+            left = parseInt(bgposition[0], 10);

+          }

+        }

+      } else {

+        left = parseInt( bgposition[0], 10);

+      }

+    }

+

+

+    if(bgposition[1] === 'auto') {

+      topPos = left / image.width * image.height;

+    } else if (bgposition[1].toString().indexOf("%") !== -1){

+      percentage = (parseFloat(bgposition[1])/100);

+      topPos =  bounds.height * percentage;

+      if(prop !== 'backgroundSize') {

+        topPos -= (backgroundSize || image).height * percentage;

+      }

+

+    } else {

+      topPos = parseInt(bgposition[1],10);

+    }

+

+    return [left, topPos];

+}

+

+_html2canvas.Util.BackgroundPosition = function( el, bounds, image, imageIndex, backgroundSize ) {

+    var result = backgroundBoundsFactory( 'backgroundPosition', el, bounds, image, imageIndex, backgroundSize );

+    return { left: result[0], top: result[1] };

+};

+

+_html2canvas.Util.BackgroundSize = function( el, bounds, image, imageIndex ) {

+    var result = backgroundBoundsFactory( 'backgroundSize', el, bounds, image, imageIndex );

+    return { width: result[0], height: result[1] };

+};

+

+_html2canvas.Util.Extend = function (options, defaults) {

+  for (var key in options) {

+    if (options.hasOwnProperty(key)) {

+      defaults[key] = options[key];

+    }

+  }

+  return defaults;

+};

+

+

+/*

+ * Derived from jQuery.contents()

+ * Copyright 2010, John Resig

+ * Dual licensed under the MIT or GPL Version 2 licenses.

+ * http://jquery.org/license

+ */

+_html2canvas.Util.Children = function( elem ) {

+  var children;

+  try {

+    children = (elem.nodeName && elem.nodeName.toUpperCase() === "IFRAME") ? elem.contentDocument || elem.contentWindow.document : (function(array) {

+      var ret = [];

+      if (array !== null) {

+        (function(first, second ) {

+          var i = first.length,

+          j = 0;

+

+          if (typeof second.length === "number") {

+            for (var l = second.length; j < l; j++) {

+              first[i++] = second[j];

+            }

+          } else {

+            while (second[j] !== undefined) {

+              first[i++] = second[j++];

+            }

+          }

+

+          first.length = i;

+

+          return first;

+        })(ret, array);

+      }

+      return ret;

+    })(elem.childNodes);

+

+  } catch (ex) {

+    _html2canvas.Util.log("html2canvas.Util.Children failed with exception: " + ex.message);

+    children = [];

+  }

+  return children;

+};

+

+_html2canvas.Util.isTransparent = function(backgroundColor) {

+  return (backgroundColor === "transparent" || backgroundColor === "rgba(0, 0, 0, 0)");

+};

+_html2canvas.Util.Font = (function () {

+

+  var fontData = {};

+

+  return function(font, fontSize, doc) {

+    if (fontData[font + "-" + fontSize] !== undefined) {

+      return fontData[font + "-" + fontSize];

+    }

+

+    var container = doc.createElement('div'),

+    img = doc.createElement('img'),

+    span = doc.createElement('span'),

+    sampleText = 'Hidden Text',

+    baseline,

+    middle,

+    metricsObj;

+

+    container.style.visibility = "hidden";

+    container.style.fontFamily = font;

+    container.style.fontSize = fontSize;

+    container.style.margin = 0;

+    container.style.padding = 0;

+

+    doc.body.appendChild(container);

+

+    // http://probablyprogramming.com/2009/03/15/the-tiniest-gif-ever (handtinywhite.gif)

+    img.src = "data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACwAAAAAAQABAAACAkQBADs=";

+    img.width = 1;

+    img.height = 1;

+

+    img.style.margin = 0;

+    img.style.padding = 0;

+    img.style.verticalAlign = "baseline";

+

+    span.style.fontFamily = font;

+    span.style.fontSize = fontSize;

+    span.style.margin = 0;

+    span.style.padding = 0;

+

+    span.appendChild(doc.createTextNode(sampleText));

+    container.appendChild(span);

+    container.appendChild(img);

+    baseline = (img.offsetTop - span.offsetTop) + 1;

+

+    container.removeChild(span);

+    container.appendChild(doc.createTextNode(sampleText));

+

+    container.style.lineHeight = "normal";

+    img.style.verticalAlign = "super";

+

+    middle = (img.offsetTop-container.offsetTop) + 1;

+    metricsObj = {

+      baseline: baseline,

+      lineWidth: 1,

+      middle: middle

+    };

+

+    fontData[font + "-" + fontSize] = metricsObj;

+

+    doc.body.removeChild(container);

+

+    return metricsObj;

+  };

+})();

+

+(function(){

+  var Util = _html2canvas.Util,

+    Generate = {};

+

+  _html2canvas.Generate = Generate;

+

+  var reGradients = [

+  /^(-webkit-linear-gradient)\(([a-z\s]+)([\w\d\.\s,%\(\)]+)\)$/,

+  /^(-o-linear-gradient)\(([a-z\s]+)([\w\d\.\s,%\(\)]+)\)$/,

+  /^(-webkit-gradient)\((linear|radial),\s((?:\d{1,3}%?)\s(?:\d{1,3}%?),\s(?:\d{1,3}%?)\s(?:\d{1,3}%?))([\w\d\.\s,%\(\)\-]+)\)$/,

+  /^(-moz-linear-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?))([\w\d\.\s,%\(\)]+)\)$/,

+  /^(-webkit-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s([a-z\-]+)([\w\d\.\s,%\(\)]+)\)$/,

+  /^(-moz-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s?([a-z\-]*)([\w\d\.\s,%\(\)]+)\)$/,

+  /^(-o-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s([a-z\-]+)([\w\d\.\s,%\(\)]+)\)$/

+  ];

+

+  /*

+ * TODO: Add IE10 vendor prefix (-ms) support

+ * TODO: Add W3C gradient (linear-gradient) support

+ * TODO: Add old Webkit -webkit-gradient(radial, ...) support

+ * TODO: Maybe some RegExp optimizations are possible ;o)

+ */

+  Generate.parseGradient = function(css, bounds) {

+    var gradient, i, len = reGradients.length, m1, stop, m2, m2Len, step, m3, tl,tr,br,bl;

+

+    for(i = 0; i < len; i+=1){

+      m1 = css.match(reGradients[i]);

+      if(m1) {

+        break;

+      }

+    }

+

+    if(m1) {

+      switch(m1[1]) {

+        case '-webkit-linear-gradient':

+        case '-o-linear-gradient':

+

+          gradient = {

+            type: 'linear',

+            x0: null,

+            y0: null,

+            x1: null,

+            y1: null,

+            colorStops: []

+          };

+

+          // get coordinates

+          m2 = m1[2].match(/\w+/g);

+          if(m2){

+            m2Len = m2.length;

+            for(i = 0; i < m2Len; i+=1){

+              switch(m2[i]) {

+                case 'top':

+                  gradient.y0 = 0;

+                  gradient.y1 = bounds.height;

+                  break;

+

+                case 'right':

+                  gradient.x0 = bounds.width;

+                  gradient.x1 = 0;

+                  break;

+

+                case 'bottom':

+                  gradient.y0 = bounds.height;

+                  gradient.y1 = 0;

+                  break;

+

+                case 'left':

+                  gradient.x0 = 0;

+                  gradient.x1 = bounds.width;

+                  break;

+              }

+            }

+          }

+          if(gradient.x0 === null && gradient.x1 === null){ // center

+            gradient.x0 = gradient.x1 = bounds.width / 2;

+          }

+          if(gradient.y0 === null && gradient.y1 === null){ // center

+            gradient.y0 = gradient.y1 = bounds.height / 2;

+          }

+

+          // get colors and stops

+          m2 = m1[3].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}(?:%|px))?)+/g);

+          if(m2){

+            m2Len = m2.length;

+            step = 1 / Math.max(m2Len - 1, 1);

+            for(i = 0; i < m2Len; i+=1){

+              m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/);

+              if(m3[2]){

+                stop = parseFloat(m3[2]);

+                if(m3[3] === '%'){

+                  stop /= 100;

+                } else { // px - stupid opera

+                  stop /= bounds.width;

+                }

+              } else {

+                stop = i * step;

+              }

+              gradient.colorStops.push({

+                color: m3[1],

+                stop: stop

+              });

+            }

+          }

+          break;

+

+        case '-webkit-gradient':

+

+          gradient = {

+            type: m1[2] === 'radial' ? 'circle' : m1[2], // TODO: Add radial gradient support for older mozilla definitions

+            x0: 0,

+            y0: 0,

+            x1: 0,

+            y1: 0,

+            colorStops: []

+          };

+

+          // get coordinates

+          m2 = m1[3].match(/(\d{1,3})%?\s(\d{1,3})%?,\s(\d{1,3})%?\s(\d{1,3})%?/);

+          if(m2){

+            gradient.x0 = (m2[1] * bounds.width) / 100;

+            gradient.y0 = (m2[2] * bounds.height) / 100;

+            gradient.x1 = (m2[3] * bounds.width) / 100;

+            gradient.y1 = (m2[4] * bounds.height) / 100;

+          }

+

+          // get colors and stops

+          m2 = m1[4].match(/((?:from|to|color-stop)\((?:[0-9\.]+,\s)?(?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)\))+/g);

+          if(m2){

+            m2Len = m2.length;

+            for(i = 0; i < m2Len; i+=1){

+              m3 = m2[i].match(/(from|to|color-stop)\(([0-9\.]+)?(?:,\s)?((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\)/);

+              stop = parseFloat(m3[2]);

+              if(m3[1] === 'from') {

+                stop = 0.0;

+              }

+              if(m3[1] === 'to') {

+                stop = 1.0;

+              }

+              gradient.colorStops.push({

+                color: m3[3],

+                stop: stop

+              });

+            }

+          }

+          break;

+

+        case '-moz-linear-gradient':

+

+          gradient = {

+            type: 'linear',

+            x0: 0,

+            y0: 0,

+            x1: 0,

+            y1: 0,

+            colorStops: []

+          };

+

+          // get coordinates

+          m2 = m1[2].match(/(\d{1,3})%?\s(\d{1,3})%?/);

+

+          // m2[1] == 0%   -> left

+          // m2[1] == 50%  -> center

+          // m2[1] == 100% -> right

+

+          // m2[2] == 0%   -> top

+          // m2[2] == 50%  -> center

+          // m2[2] == 100% -> bottom

+

+          if(m2){

+            gradient.x0 = (m2[1] * bounds.width) / 100;

+            gradient.y0 = (m2[2] * bounds.height) / 100;

+            gradient.x1 = bounds.width - gradient.x0;

+            gradient.y1 = bounds.height - gradient.y0;

+          }

+

+          // get colors and stops

+          m2 = m1[3].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}%)?)+/g);

+          if(m2){

+            m2Len = m2.length;

+            step = 1 / Math.max(m2Len - 1, 1);

+            for(i = 0; i < m2Len; i+=1){

+              m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%)?/);

+              if(m3[2]){

+                stop = parseFloat(m3[2]);

+                if(m3[3]){ // percentage

+                  stop /= 100;

+                }

+              } else {

+                stop = i * step;

+              }

+              gradient.colorStops.push({

+                color: m3[1],

+                stop: stop

+              });

+            }

+          }

+          break;

+

+        case '-webkit-radial-gradient':

+        case '-moz-radial-gradient':

+        case '-o-radial-gradient':

+

+          gradient = {

+            type: 'circle',

+            x0: 0,

+            y0: 0,

+            x1: bounds.width,

+            y1: bounds.height,

+            cx: 0,

+            cy: 0,

+            rx: 0,

+            ry: 0,

+            colorStops: []

+          };

+

+          // center

+          m2 = m1[2].match(/(\d{1,3})%?\s(\d{1,3})%?/);

+          if(m2){

+            gradient.cx = (m2[1] * bounds.width) / 100;

+            gradient.cy = (m2[2] * bounds.height) / 100;

+          }

+

+          // size

+          m2 = m1[3].match(/\w+/);

+          m3 = m1[4].match(/[a-z\-]*/);

+          if(m2 && m3){

+            switch(m3[0]){

+              case 'farthest-corner':

+              case 'cover': // is equivalent to farthest-corner

+              case '': // mozilla removes "cover" from definition :(

+                tl = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.cy, 2));

+                tr = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));

+                br = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));

+                bl = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.cy, 2));

+                gradient.rx = gradient.ry = Math.max(tl, tr, br, bl);

+                break;

+              case 'closest-corner':

+                tl = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.cy, 2));

+                tr = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));

+                br = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));

+                bl = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.cy, 2));

+                gradient.rx = gradient.ry = Math.min(tl, tr, br, bl);

+                break;

+              case 'farthest-side':

+                if(m2[0] === 'circle'){

+                  gradient.rx = gradient.ry = Math.max(

+                    gradient.cx,

+                    gradient.cy,

+                    gradient.x1 - gradient.cx,

+                    gradient.y1 - gradient.cy

+                    );

+                } else { // ellipse

+

+                  gradient.type = m2[0];

+

+                  gradient.rx = Math.max(

+                    gradient.cx,

+                    gradient.x1 - gradient.cx

+                    );

+                  gradient.ry = Math.max(

+                    gradient.cy,

+                    gradient.y1 - gradient.cy

+                    );

+                }

+                break;

+              case 'closest-side':

+              case 'contain': // is equivalent to closest-side

+                if(m2[0] === 'circle'){

+                  gradient.rx = gradient.ry = Math.min(

+                    gradient.cx,

+                    gradient.cy,

+                    gradient.x1 - gradient.cx,

+                    gradient.y1 - gradient.cy

+                    );

+                } else { // ellipse

+

+                  gradient.type = m2[0];

+

+                  gradient.rx = Math.min(

+                    gradient.cx,

+                    gradient.x1 - gradient.cx

+                    );

+                  gradient.ry = Math.min(

+                    gradient.cy,

+                    gradient.y1 - gradient.cy

+                    );

+                }

+                break;

+

+            // TODO: add support for "30px 40px" sizes (webkit only)

+            }

+          }

+

+          // color stops

+          m2 = m1[5].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}(?:%|px))?)+/g);

+          if(m2){

+            m2Len = m2.length;

+            step = 1 / Math.max(m2Len - 1, 1);

+            for(i = 0; i < m2Len; i+=1){

+              m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/);

+              if(m3[2]){

+                stop = parseFloat(m3[2]);

+                if(m3[3] === '%'){

+                  stop /= 100;

+                } else { // px - stupid opera

+                  stop /= bounds.width;

+                }

+              } else {

+                stop = i * step;

+              }

+              gradient.colorStops.push({

+                color: m3[1],

+                stop: stop

+              });

+            }

+          }

+          break;

+      }

+    }

+

+    return gradient;

+  };

+

+  function addScrollStops(grad) {

+    return function(colorStop) {

+      try {

+        grad.addColorStop(colorStop.stop, colorStop.color);

+      }

+      catch(e) {

+        Util.log(['failed to add color stop: ', e, '; tried to add: ', colorStop]);

+      }

+    };

+  }

+

+  Generate.Gradient = function(src, bounds) {

+    if(bounds.width === 0 || bounds.height === 0) {

+      return;

+    }

+

+    var canvas = document.createElement('canvas'),

+    ctx = canvas.getContext('2d'),

+    gradient, grad;

+

+    canvas.width = bounds.width;

+    canvas.height = bounds.height;

+

+    // TODO: add support for multi defined background gradients

+    gradient = _html2canvas.Generate.parseGradient(src, bounds);

+

+    if(gradient) {

+      switch(gradient.type) {

+        case 'linear':

+          grad = ctx.createLinearGradient(gradient.x0, gradient.y0, gradient.x1, gradient.y1);

+          gradient.colorStops.forEach(addScrollStops(grad));

+          ctx.fillStyle = grad;

+          ctx.fillRect(0, 0, bounds.width, bounds.height);

+          break;

+

+        case 'circle':

+          grad = ctx.createRadialGradient(gradient.cx, gradient.cy, 0, gradient.cx, gradient.cy, gradient.rx);

+          gradient.colorStops.forEach(addScrollStops(grad));

+          ctx.fillStyle = grad;

+          ctx.fillRect(0, 0, bounds.width, bounds.height);

+          break;

+

+        case 'ellipse':

+          var canvasRadial = document.createElement('canvas'),

+            ctxRadial = canvasRadial.getContext('2d'),

+            ri = Math.max(gradient.rx, gradient.ry),

+            di = ri * 2;

+

+          canvasRadial.width = canvasRadial.height = di;

+

+          grad = ctxRadial.createRadialGradient(gradient.rx, gradient.ry, 0, gradient.rx, gradient.ry, ri);

+          gradient.colorStops.forEach(addScrollStops(grad));

+

+          ctxRadial.fillStyle = grad;

+          ctxRadial.fillRect(0, 0, di, di);

+

+          ctx.fillStyle = gradient.colorStops[gradient.colorStops.length - 1].color;

+          ctx.fillRect(0, 0, canvas.width, canvas.height);

+          ctx.drawImage(canvasRadial, gradient.cx - gradient.rx, gradient.cy - gradient.ry, 2 * gradient.rx, 2 * gradient.ry);

+          break;

+      }

+    }

+

+    return canvas;

+  };

+

+  Generate.ListAlpha = function(number) {

+    var tmp = "",

+    modulus;

+

+    do {

+      modulus = number % 26;

+      tmp = String.fromCharCode((modulus) + 64) + tmp;

+      number = number / 26;

+    }while((number*26) > 26);

+

+    return tmp;

+  };

+

+  Generate.ListRoman = function(number) {

+    var romanArray = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"],

+    decimal = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1],

+    roman = "",

+    v,

+    len = romanArray.length;

+

+    if (number <= 0 || number >= 4000) {

+      return number;

+    }

+

+    for (v=0; v < len; v+=1) {

+      while (number >= decimal[v]) {

+        number -= decimal[v];

+        roman += romanArray[v];

+      }

+    }

+

+    return roman;

+  };

+})();

+function h2cRenderContext(width, height) {

+  var storage = [];

+  return {

+    storage: storage,

+    width: width,

+    height: height,

+    clip: function() {

+      storage.push({

+        type: "function",

+        name: "clip",

+        'arguments': arguments

+      });

+    },

+    translate: function() {

+      storage.push({

+        type: "function",

+        name: "translate",

+        'arguments': arguments

+      });

+    },

+    fill: function() {

+      storage.push({

+        type: "function",

+        name: "fill",

+        'arguments': arguments

+      });

+    },

+    save: function() {

+      storage.push({

+        type: "function",

+        name: "save",

+        'arguments': arguments

+      });

+    },

+    restore: function() {

+      storage.push({

+        type: "function",

+        name: "restore",

+        'arguments': arguments

+      });

+    },

+    fillRect: function () {

+      storage.push({

+        type: "function",

+        name: "fillRect",

+        'arguments': arguments

+      });

+    },

+    createPattern: function() {

+      storage.push({

+        type: "function",

+        name: "createPattern",

+        'arguments': arguments

+      });

+    },

+    drawShape: function() {

+

+      var shape = [];

+

+      storage.push({

+        type: "function",

+        name: "drawShape",

+        'arguments': shape

+      });

+

+      return {

+        moveTo: function() {

+          shape.push({

+            name: "moveTo",

+            'arguments': arguments

+          });

+        },

+        lineTo: function() {

+          shape.push({

+            name: "lineTo",

+            'arguments': arguments

+          });

+        },

+        arcTo: function() {

+          shape.push({

+            name: "arcTo",

+            'arguments': arguments

+          });

+        },

+        bezierCurveTo: function() {

+          shape.push({

+            name: "bezierCurveTo",

+            'arguments': arguments

+          });

+        },

+        quadraticCurveTo: function() {

+          shape.push({

+            name: "quadraticCurveTo",

+            'arguments': arguments

+          });

+        }

+      };

+

+    },

+    drawImage: function () {

+      storage.push({

+        type: "function",

+        name: "drawImage",

+        'arguments': arguments

+      });

+    },

+    fillText: function () {

+      storage.push({

+        type: "function",

+        name: "fillText",

+        'arguments': arguments

+      });

+    },

+    setVariable: function (variable, value) {

+      storage.push({

+        type: "variable",

+        name: variable,

+        'arguments': value

+      });

+      return value;

+    }

+  };

+}

+_html2canvas.Parse = function (images, options) {

+  window.scroll(0,0);

+

+  var element = (( options.elements === undefined ) ? document.body : options.elements[0]), // select body by default

+  numDraws = 0,

+  doc = element.ownerDocument,

+  Util = _html2canvas.Util,

+  support = Util.Support(options, doc),

+  ignoreElementsRegExp = new RegExp("(" + options.ignoreElements + ")"),

+  body = doc.body,

+  getCSS = Util.getCSS,

+  pseudoHide = "___html2canvas___pseudoelement",

+  hidePseudoElements = doc.createElement('style');

+

+  hidePseudoElements.innerHTML = '.' + pseudoHide + '-before:before { content: "" !important; display: none !important; }' +

+  '.' + pseudoHide + '-after:after { content: "" !important; display: none !important; }';

+

+  body.appendChild(hidePseudoElements);

+

+  images = images || {};

+

+  function documentWidth () {

+    return Math.max(

+      Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth),

+      Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth),

+      Math.max(doc.body.clientWidth, doc.documentElement.clientWidth)

+      );

+  }

+

+  function documentHeight () {

+    return Math.max(

+      Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight),

+      Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight),

+      Math.max(doc.body.clientHeight, doc.documentElement.clientHeight)

+      );

+  }

+

+  function getCSSInt(element, attribute) {

+    var val = parseInt(getCSS(element, attribute), 10);

+    return (isNaN(val)) ? 0 : val; // borders in old IE are throwing 'medium' for demo.html

+  }

+

+  function renderRect (ctx, x, y, w, h, bgcolor) {

+    if (bgcolor !== "transparent"){

+      ctx.setVariable("fillStyle", bgcolor);

+      ctx.fillRect(x, y, w, h);

+      numDraws+=1;

+    }

+  }

+

+  function capitalize(m, p1, p2) {

+    if (m.length > 0) {

+      return p1 + p2.toUpperCase();

+    }

+  }

+

+  function textTransform (text, transform) {

+    switch(transform){

+      case "lowercase":

+        return text.toLowerCase();

+      case "capitalize":

+        return text.replace( /(^|\s|:|-|\(|\))([a-z])/g, capitalize);

+      case "uppercase":

+        return text.toUpperCase();

+      default:

+        return text;

+    }

+  }

+

+  function noLetterSpacing(letter_spacing) {

+    return (/^(normal|none|0px)$/.test(letter_spacing));

+  }

+

+  function drawText(currentText, x, y, ctx){

+    if (currentText !== null && Util.trimText(currentText).length > 0) {

+      ctx.fillText(currentText, x, y);

+      numDraws+=1;

+    }

+  }

+

+  function setTextVariables(ctx, el, text_decoration, color) {

+    var align = false,

+    bold = getCSS(el, "fontWeight"),

+    family = getCSS(el, "fontFamily"),

+    size = getCSS(el, "fontSize"),

+    shadows = Util.parseTextShadows(getCSS(el, "textShadow"));

+

+    switch(parseInt(bold, 10)){

+      case 401:

+        bold = "bold";

+        break;

+      case 400:

+        bold = "normal";

+        break;

+    }

+

+    ctx.setVariable("fillStyle", color);

+    ctx.setVariable("font", [getCSS(el, "fontStyle"), getCSS(el, "fontVariant"), bold, size, family].join(" "));

+    ctx.setVariable("textAlign", (align) ? "right" : "left");

+

+    if (shadows.length) {

+      // TODO: support multiple text shadows

+      // apply the first text shadow

+      ctx.setVariable("shadowColor", shadows[0].color);

+      ctx.setVariable("shadowOffsetX", shadows[0].offsetX);

+      ctx.setVariable("shadowOffsetY", shadows[0].offsetY);

+      ctx.setVariable("shadowBlur", shadows[0].blur);

+    }

+

+    if (text_decoration !== "none"){

+      return Util.Font(family, size, doc);

+    }

+  }

+

+  function renderTextDecoration(ctx, text_decoration, bounds, metrics, color) {

+    switch(text_decoration) {

+      case "underline":

+        // Draws a line at the baseline of the font

+        // TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size

+        renderRect(ctx, bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 1, color);

+        break;

+      case "overline":

+        renderRect(ctx, bounds.left, Math.round(bounds.top), bounds.width, 1, color);

+        break;

+      case "line-through":

+        // TODO try and find exact position for line-through

+        renderRect(ctx, bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 1, color);

+        break;

+    }

+  }

+

+  function getTextBounds(state, text, textDecoration, isLast, transform) {

+    var bounds;

+    if (support.rangeBounds && !transform) {

+      if (textDecoration !== "none" || Util.trimText(text).length !== 0) {

+        bounds = textRangeBounds(text, state.node, state.textOffset);

+      }

+      state.textOffset += text.length;

+    } else if (state.node && typeof state.node.nodeValue === "string" ){

+      var newTextNode = (isLast) ? state.node.splitText(text.length) : null;

+      bounds = textWrapperBounds(state.node, transform);

+      state.node = newTextNode;

+    }

+    return bounds;

+  }

+

+  function textRangeBounds(text, textNode, textOffset) {

+    var range = doc.createRange();

+    range.setStart(textNode, textOffset);

+    range.setEnd(textNode, textOffset + text.length);

+    return range.getBoundingClientRect();

+  }

+

+  function textWrapperBounds(oldTextNode, transform) {

+    var parent = oldTextNode.parentNode,

+    wrapElement = doc.createElement('wrapper'),

+    backupText = oldTextNode.cloneNode(true);

+

+    wrapElement.appendChild(oldTextNode.cloneNode(true));

+    parent.replaceChild(wrapElement, oldTextNode);

+

+    var bounds = transform ? Util.OffsetBounds(wrapElement) : Util.Bounds(wrapElement);

+    parent.replaceChild(backupText, wrapElement);

+    return bounds;

+  }

+

+  function renderText(el, textNode, stack) {

+    var ctx = stack.ctx,

+    color = getCSS(el, "color"),

+    textDecoration = getCSS(el, "textDecoration"),

+    textAlign = getCSS(el, "textAlign"),

+    metrics,

+    textList,

+    state = {

+      node: textNode,

+      textOffset: 0

+    };

+

+    if (Util.trimText(textNode.nodeValue).length > 0) {

+      textNode.nodeValue = textTransform(textNode.nodeValue, getCSS(el, "textTransform"));

+      textAlign = textAlign.replace(["-webkit-auto"],["auto"]);

+

+      textList = (!options.letterRendering && /^(left|right|justify|auto)$/.test(textAlign) && noLetterSpacing(getCSS(el, "letterSpacing"))) ?

+      textNode.nodeValue.split(/(\b| )/)

+      : textNode.nodeValue.split("");

+

+      metrics = setTextVariables(ctx, el, textDecoration, color);

+

+      if (options.chinese) {

+        textList.forEach(function(word, index) {

+          if (/.*[\u4E00-\u9FA5].*$/.test(word)) {

+            word = word.split("");

+            word.unshift(index, 1);

+            textList.splice.apply(textList, word);

+          }

+        });

+      }

+

+      textList.forEach(function(text, index) {

+        var bounds = getTextBounds(state, text, textDecoration, (index < textList.length - 1), stack.transform.matrix);

+        if (bounds) {

+          drawText(text, bounds.left, bounds.bottom, ctx);

+          renderTextDecoration(ctx, textDecoration, bounds, metrics, color);

+        }

+      });

+    }

+  }

+

+  function listPosition (element, val) {

+    var boundElement = doc.createElement( "boundelement" ),

+    originalType,

+    bounds;

+

+    boundElement.style.display = "inline";

+

+    originalType = element.style.listStyleType;

+    element.style.listStyleType = "none";

+

+    boundElement.appendChild(doc.createTextNode(val));

+

+    element.insertBefore(boundElement, element.firstChild);

+

+    bounds = Util.Bounds(boundElement);

+    element.removeChild(boundElement);

+    element.style.listStyleType = originalType;

+    return bounds;

+  }

+

+  function elementIndex(el) {

+    var i = -1,

+    count = 1,

+    childs = el.parentNode.childNodes;

+

+    if (el.parentNode) {

+      while(childs[++i] !== el) {

+        if (childs[i].nodeType === 1) {

+          count++;

+        }

+      }

+      return count;

+    } else {

+      return -1;

+    }

+  }

+

+  function listItemText(element, type) {

+    var currentIndex = elementIndex(element), text;

+    switch(type){

+      case "decimal":

+        text = currentIndex;

+        break;

+      case "decimal-leading-zero":

+        text = (currentIndex.toString().length === 1) ? currentIndex = "0" + currentIndex.toString() : currentIndex.toString();

+        break;

+      case "upper-roman":

+        text = _html2canvas.Generate.ListRoman( currentIndex );

+        break;

+      case "lower-roman":

+        text = _html2canvas.Generate.ListRoman( currentIndex ).toLowerCase();

+        break;

+      case "lower-alpha":

+        text = _html2canvas.Generate.ListAlpha( currentIndex ).toLowerCase();

+        break;

+      case "upper-alpha":

+        text = _html2canvas.Generate.ListAlpha( currentIndex );

+        break;

+    }

+

+    return text + ". ";

+  }

+

+  function renderListItem(element, stack, elBounds) {

+    var x,

+    text,

+    ctx = stack.ctx,

+    type = getCSS(element, "listStyleType"),

+    listBounds;

+

+    if (/^(decimal|decimal-leading-zero|upper-alpha|upper-latin|upper-roman|lower-alpha|lower-greek|lower-latin|lower-roman)$/i.test(type)) {

+      text = listItemText(element, type);

+      listBounds = listPosition(element, text);

+      setTextVariables(ctx, element, "none", getCSS(element, "color"));

+

+      if (getCSS(element, "listStylePosition") === "inside") {

+        ctx.setVariable("textAlign", "left");

+        x = elBounds.left;

+      } else {

+        return;

+      }

+

+      drawText(text, x, listBounds.bottom, ctx);

+    }

+  }

+

+  function loadImage (src){

+    var img = images[src];

+    return (img && img.succeeded === true) ? img.img : false;

+  }

+

+  function clipBounds(src, dst){

+    var x = Math.max(src.left, dst.left),

+    y = Math.max(src.top, dst.top),

+    x2 = Math.min((src.left + src.width), (dst.left + dst.width)),

+    y2 = Math.min((src.top + src.height), (dst.top + dst.height));

+

+    return {

+      left:x,

+      top:y,

+      width:x2-x,

+      height:y2-y

+    };

+  }

+

+  function setZ(element, stack, parentStack){

+    var newContext,

+    isPositioned = stack.cssPosition !== 'static',

+    zIndex = isPositioned ? getCSS(element, 'zIndex') : 'auto',

+    opacity = getCSS(element, 'opacity'),

+    isFloated = getCSS(element, 'cssFloat') !== 'none';

+

+    // https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context

+    // When a new stacking context should be created:

+    // the root element (HTML),

+    // positioned (absolutely or relatively) with a z-index value other than "auto",

+    // elements with an opacity value less than 1. (See the specification for opacity),

+    // on mobile WebKit and Chrome 22+, position: fixed always creates a new stacking context, even when z-index is "auto" (See this post)

+

+    stack.zIndex = newContext = h2czContext(zIndex);

+    newContext.isPositioned = isPositioned;

+    newContext.isFloated = isFloated;

+    newContext.opacity = opacity;

+    newContext.ownStacking = (zIndex !== 'auto' || opacity < 1);

+

+    if (parentStack) {

+      parentStack.zIndex.children.push(stack);

+    }

+  }

+

+  function renderImage(ctx, element, image, bounds, borders) {

+

+    var paddingLeft = getCSSInt(element, 'paddingLeft'),

+    paddingTop = getCSSInt(element, 'paddingTop'),

+    paddingRight = getCSSInt(element, 'paddingRight'),

+    paddingBottom = getCSSInt(element, 'paddingBottom');

+

+    drawImage(

+      ctx,

+      image,

+      0, //sx

+      0, //sy

+      image.width, //sw

+      image.height, //sh

+      bounds.left + paddingLeft + borders[3].width, //dx

+      bounds.top + paddingTop + borders[0].width, // dy

+      bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight), //dw

+      bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom) //dh

+      );

+  }

+

+  function getBorderData(element) {

+    return ["Top", "Right", "Bottom", "Left"].map(function(side) {

+      return {

+        width: getCSSInt(element, 'border' + side + 'Width'),

+        color: getCSS(element, 'border' + side + 'Color')

+      };

+    });

+  }

+

+  function getBorderRadiusData(element) {

+    return ["TopLeft", "TopRight", "BottomRight", "BottomLeft"].map(function(side) {

+      return getCSS(element, 'border' + side + 'Radius');

+    });

+  }

+

+  var getCurvePoints = (function(kappa) {

+

+    return function(x, y, r1, r2) {

+      var ox = (r1) * kappa, // control point offset horizontal

+      oy = (r2) * kappa, // control point offset vertical

+      xm = x + r1, // x-middle

+      ym = y + r2; // y-middle

+      return {

+        topLeft: bezierCurve({

+          x:x,

+          y:ym

+        }, {

+          x:x,

+          y:ym - oy

+        }, {

+          x:xm - ox,

+          y:y

+        }, {

+          x:xm,

+          y:y

+        }),

+        topRight: bezierCurve({

+          x:x,

+          y:y

+        }, {

+          x:x + ox,

+          y:y

+        }, {

+          x:xm,

+          y:ym - oy

+        }, {

+          x:xm,

+          y:ym

+        }),

+        bottomRight: bezierCurve({

+          x:xm,

+          y:y

+        }, {

+          x:xm,

+          y:y + oy

+        }, {

+          x:x + ox,

+          y:ym

+        }, {

+          x:x,

+          y:ym

+        }),

+        bottomLeft: bezierCurve({

+          x:xm,

+          y:ym

+        }, {

+          x:xm - ox,

+          y:ym

+        }, {

+          x:x,

+          y:y + oy

+        }, {

+          x:x,

+          y:y

+        })

+      };

+    };

+  })(4 * ((Math.sqrt(2) - 1) / 3));

+

+  function bezierCurve(start, startControl, endControl, end) {

+

+    var lerp = function (a, b, t) {

+      return {

+        x:a.x + (b.x - a.x) * t,

+        y:a.y + (b.y - a.y) * t

+      };

+    };

+

+    return {

+      start: start,

+      startControl: startControl,

+      endControl: endControl,

+      end: end,

+      subdivide: function(t) {

+        var ab = lerp(start, startControl, t),

+        bc = lerp(startControl, endControl, t),

+        cd = lerp(endControl, end, t),

+        abbc = lerp(ab, bc, t),

+        bccd = lerp(bc, cd, t),

+        dest = lerp(abbc, bccd, t);

+        return [bezierCurve(start, ab, abbc, dest), bezierCurve(dest, bccd, cd, end)];

+      },

+      curveTo: function(borderArgs) {

+        borderArgs.push(["bezierCurve", startControl.x, startControl.y, endControl.x, endControl.y, end.x, end.y]);

+      },

+      curveToReversed: function(borderArgs) {

+        borderArgs.push(["bezierCurve", endControl.x, endControl.y, startControl.x, startControl.y, start.x, start.y]);

+      }

+    };

+  }

+

+  function parseCorner(borderArgs, radius1, radius2, corner1, corner2, x, y) {

+    if (radius1[0] > 0 || radius1[1] > 0) {

+      borderArgs.push(["line", corner1[0].start.x, corner1[0].start.y]);

+      corner1[0].curveTo(borderArgs);

+      corner1[1].curveTo(borderArgs);

+    } else {

+      borderArgs.push(["line", x, y]);

+    }

+

+    if (radius2[0] > 0 || radius2[1] > 0) {

+      borderArgs.push(["line", corner2[0].start.x, corner2[0].start.y]);

+    }

+  }

+

+  function drawSide(borderData, radius1, radius2, outer1, inner1, outer2, inner2) {

+    var borderArgs = [];

+

+    if (radius1[0] > 0 || radius1[1] > 0) {

+      borderArgs.push(["line", outer1[1].start.x, outer1[1].start.y]);

+      outer1[1].curveTo(borderArgs);

+    } else {

+      borderArgs.push([ "line", borderData.c1[0], borderData.c1[1]]);

+    }

+

+    if (radius2[0] > 0 || radius2[1] > 0) {

+      borderArgs.push(["line", outer2[0].start.x, outer2[0].start.y]);

+      outer2[0].curveTo(borderArgs);

+      borderArgs.push(["line", inner2[0].end.x, inner2[0].end.y]);

+      inner2[0].curveToReversed(borderArgs);

+    } else {

+      borderArgs.push([ "line", borderData.c2[0], borderData.c2[1]]);

+      borderArgs.push([ "line", borderData.c3[0], borderData.c3[1]]);

+    }

+

+    if (radius1[0] > 0 || radius1[1] > 0) {

+      borderArgs.push(["line", inner1[1].end.x, inner1[1].end.y]);

+      inner1[1].curveToReversed(borderArgs);

+    } else {

+      borderArgs.push([ "line", borderData.c4[0], borderData.c4[1]]);

+    }

+

+    return borderArgs;

+  }

+

+  function calculateCurvePoints(bounds, borderRadius, borders) {

+

+    var x = bounds.left,

+    y = bounds.top,

+    width = bounds.width,

+    height = bounds.height,

+

+    tlh = borderRadius[0][0],

+    tlv = borderRadius[0][1],

+    trh = borderRadius[1][0],

+    trv = borderRadius[1][1],

+    brh = borderRadius[2][0],

+    brv = borderRadius[2][1],

+    blh = borderRadius[3][0],

+    blv = borderRadius[3][1],

+

+    topWidth = width - trh,

+    rightHeight = height - brv,

+    bottomWidth = width - brh,

+    leftHeight = height - blv;

+

+    return {

+      topLeftOuter: getCurvePoints(

+        x,

+        y,

+        tlh,

+        tlv

+        ).topLeft.subdivide(0.5),

+

+      topLeftInner: getCurvePoints(

+        x + borders[3].width,

+        y + borders[0].width,

+        Math.max(0, tlh - borders[3].width),

+        Math.max(0, tlv - borders[0].width)

+        ).topLeft.subdivide(0.5),

+

+      topRightOuter: getCurvePoints(

+        x + topWidth,

+        y,

+        trh,

+        trv

+        ).topRight.subdivide(0.5),

+

+      topRightInner: getCurvePoints(

+        x + Math.min(topWidth, width + borders[3].width),

+        y + borders[0].width,

+        (topWidth > width + borders[3].width) ? 0 :trh - borders[3].width,

+        trv - borders[0].width

+        ).topRight.subdivide(0.5),

+

+      bottomRightOuter: getCurvePoints(

+        x + bottomWidth,

+        y + rightHeight,

+        brh,

+        brv

+        ).bottomRight.subdivide(0.5),

+

+      bottomRightInner: getCurvePoints(

+        x + Math.min(bottomWidth, width + borders[3].width),

+        y + Math.min(rightHeight, height + borders[0].width),

+        Math.max(0, brh - borders[1].width),

+        Math.max(0, brv - borders[2].width)

+        ).bottomRight.subdivide(0.5),

+

+      bottomLeftOuter: getCurvePoints(

+        x,

+        y + leftHeight,

+        blh,

+        blv

+        ).bottomLeft.subdivide(0.5),

+

+      bottomLeftInner: getCurvePoints(

+        x + borders[3].width,

+        y + leftHeight,

+        Math.max(0, blh - borders[3].width),

+        Math.max(0, blv - borders[2].width)

+        ).bottomLeft.subdivide(0.5)

+    };

+  }

+

+  function getBorderClip(element, borderPoints, borders, radius, bounds) {

+    var backgroundClip = getCSS(element, 'backgroundClip'),

+    borderArgs = [];

+

+    switch(backgroundClip) {

+      case "content-box":

+      case "padding-box":

+        parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftInner, borderPoints.topRightInner, bounds.left + borders[3].width, bounds.top + borders[0].width);

+        parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightInner, borderPoints.bottomRightInner, bounds.left + bounds.width - borders[1].width, bounds.top + borders[0].width);

+        parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightInner, borderPoints.bottomLeftInner, bounds.left + bounds.width - borders[1].width, bounds.top + bounds.height - borders[2].width);

+        parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftInner, borderPoints.topLeftInner, bounds.left + borders[3].width, bounds.top + bounds.height - borders[2].width);

+        break;

+

+      default:

+        parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftOuter, borderPoints.topRightOuter, bounds.left, bounds.top);

+        parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightOuter, borderPoints.bottomRightOuter, bounds.left + bounds.width, bounds.top);

+        parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightOuter, borderPoints.bottomLeftOuter, bounds.left + bounds.width, bounds.top + bounds.height);

+        parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftOuter, borderPoints.topLeftOuter, bounds.left, bounds.top + bounds.height);

+        break;

+    }

+

+    return borderArgs;

+  }

+

+  function parseBorders(element, bounds, borders){

+    var x = bounds.left,

+    y = bounds.top,

+    width = bounds.width,

+    height = bounds.height,

+    borderSide,

+    bx,

+    by,

+    bw,

+    bh,

+    borderArgs,

+    // http://www.w3.org/TR/css3-background/#the-border-radius

+    borderRadius = getBorderRadiusData(element),

+    borderPoints = calculateCurvePoints(bounds, borderRadius, borders),

+    borderData = {

+      clip: getBorderClip(element, borderPoints, borders, borderRadius, bounds),

+      borders: []

+    };

+

+    for (borderSide = 0; borderSide < 4; borderSide++) {

+

+      if (borders[borderSide].width > 0) {

+        bx = x;

+        by = y;

+        bw = width;

+        bh = height - (borders[2].width);

+

+        switch(borderSide) {

+          case 0:

+            // top border

+            bh = borders[0].width;

+

+            borderArgs = drawSide({

+              c1: [bx, by],

+              c2: [bx + bw, by],

+              c3: [bx + bw - borders[1].width, by + bh],

+              c4: [bx + borders[3].width, by + bh]

+            }, borderRadius[0], borderRadius[1],

+            borderPoints.topLeftOuter, borderPoints.topLeftInner, borderPoints.topRightOuter, borderPoints.topRightInner);

+            break;

+          case 1:

+            // right border

+            bx = x + width - (borders[1].width);

+            bw = borders[1].width;

+

+            borderArgs = drawSide({

+              c1: [bx + bw, by],

+              c2: [bx + bw, by + bh + borders[2].width],

+              c3: [bx, by + bh],

+              c4: [bx, by + borders[0].width]

+            }, borderRadius[1], borderRadius[2],

+            borderPoints.topRightOuter, borderPoints.topRightInner, borderPoints.bottomRightOuter, borderPoints.bottomRightInner);

+            break;

+          case 2:

+            // bottom border

+            by = (by + height) - (borders[2].width);

+            bh = borders[2].width;

+

+            borderArgs = drawSide({

+              c1: [bx + bw, by + bh],

+              c2: [bx, by + bh],

+              c3: [bx + borders[3].width, by],

+              c4: [bx + bw - borders[3].width, by]

+            }, borderRadius[2], borderRadius[3],

+            borderPoints.bottomRightOuter, borderPoints.bottomRightInner, borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner);

+            break;

+          case 3:

+            // left border

+            bw = borders[3].width;

+

+            borderArgs = drawSide({

+              c1: [bx, by + bh + borders[2].width],

+              c2: [bx, by],

+              c3: [bx + bw, by + borders[0].width],

+              c4: [bx + bw, by + bh]

+            }, borderRadius[3], borderRadius[0],

+            borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner, borderPoints.topLeftOuter, borderPoints.topLeftInner);

+            break;

+        }

+

+        borderData.borders.push({

+          args: borderArgs,

+          color: borders[borderSide].color

+        });

+

+      }

+    }

+

+    return borderData;

+  }

+

+  function createShape(ctx, args) {

+    var shape = ctx.drawShape();

+    args.forEach(function(border, index) {

+      shape[(index === 0) ? "moveTo" : border[0] + "To" ].apply(null, border.slice(1));

+    });

+    return shape;

+  }

+

+  function renderBorders(ctx, borderArgs, color) {

+    if (color !== "transparent") {

+      ctx.setVariable( "fillStyle", color);

+      createShape(ctx, borderArgs);

+      ctx.fill();

+      numDraws+=1;

+    }

+  }

+

+  function renderFormValue (el, bounds, stack){

+

+    var valueWrap = doc.createElement('valuewrap'),

+    cssPropertyArray = ['lineHeight','textAlign','fontFamily','color','fontSize','paddingLeft','paddingTop','width','height','border','borderLeftWidth','borderTopWidth'],

+    textValue,

+    textNode;

+

+    cssPropertyArray.forEach(function(property) {

+      try {

+        valueWrap.style[property] = getCSS(el, property);

+      } catch(e) {

+        // Older IE has issues with "border"

+        Util.log("html2canvas: Parse: Exception caught in renderFormValue: " + e.message);

+      }

+    });

+

+    valueWrap.style.borderColor = "black";

+    valueWrap.style.borderStyle = "solid";

+    valueWrap.style.display = "block";

+    valueWrap.style.position = "absolute";

+

+    if (/^(submit|reset|button|text|password)$/.test(el.type) || el.nodeName === "SELECT"){

+      valueWrap.style.lineHeight = getCSS(el, "height");

+    }

+

+    valueWrap.style.top = bounds.top + "px";

+    valueWrap.style.left = bounds.left + "px";

+

+    textValue = (el.nodeName === "SELECT") ? (el.options[el.selectedIndex] || 0).text : el.value;

+    if(!textValue) {

+      textValue = el.placeholder;

+    }

+

+    textNode = doc.createTextNode(textValue);

+

+    valueWrap.appendChild(textNode);

+    body.appendChild(valueWrap);

+

+    renderText(el, textNode, stack);

+    body.removeChild(valueWrap);

+  }

+

+  function drawImage (ctx) {

+    ctx.drawImage.apply(ctx, Array.prototype.slice.call(arguments, 1));

+    numDraws+=1;

+  }

+

+  function getPseudoElement(el, which) {

+    var elStyle = window.getComputedStyle(el, which);

+    if(!elStyle || !elStyle.content || elStyle.content === "none" || elStyle.content === "-moz-alt-content" || elStyle.display === "none") {

+      return;

+    }

+    var content = elStyle.content + '',

+    first = content.substr( 0, 1 );

+    //strips quotes

+    if(first === content.substr( content.length - 1 ) && first.match(/'|"/)) {

+      content = content.substr( 1, content.length - 2 );

+    }

+

+    var isImage = content.substr( 0, 3 ) === 'url',

+    elps = document.createElement( isImage ? 'img' : 'span' );

+

+    elps.className = pseudoHide + "-before " + pseudoHide + "-after";

+

+    Object.keys(elStyle).filter(indexedProperty).forEach(function(prop) {

+      // Prevent assigning of read only CSS Rules, ex. length, parentRule

+      try {

+        elps.style[prop] = elStyle[prop];

+      } catch (e) {

+        Util.log(['Tried to assign readonly property ', prop, 'Error:', e]);

+      }

+    });

+

+    if(isImage) {

+      elps.src = Util.parseBackgroundImage(content)[0].args[0];

+    } else {

+      elps.innerHTML = content;

+    }

+    return elps;

+  }

+

+  function indexedProperty(property) {

+    return (isNaN(window.parseInt(property, 10)));

+  }

+

+  function injectPseudoElements(el, stack) {

+    var before = getPseudoElement(el, ':before'),

+    after = getPseudoElement(el, ':after');

+    if(!before && !after) {

+      return;

+    }

+

+    if(before) {

+      el.className += " " + pseudoHide + "-before";

+      el.parentNode.insertBefore(before, el);

+      parseElement(before, stack, true);

+      el.parentNode.removeChild(before);

+      el.className = el.className.replace(pseudoHide + "-before", "").trim();

+    }

+

+    if (after) {

+      el.className += " " + pseudoHide + "-after";

+      el.appendChild(after);

+      parseElement(after, stack, true);

+      el.removeChild(after);

+      el.className = el.className.replace(pseudoHide + "-after", "").trim();

+    }

+

+  }

+

+  function renderBackgroundRepeat(ctx, image, backgroundPosition, bounds) {

+    var offsetX = Math.round(bounds.left + backgroundPosition.left),

+    offsetY = Math.round(bounds.top + backgroundPosition.top);

+

+    ctx.createPattern(image);

+    ctx.translate(offsetX, offsetY);

+    ctx.fill();

+    ctx.translate(-offsetX, -offsetY);

+  }

+

+  function backgroundRepeatShape(ctx, image, backgroundPosition, bounds, left, top, width, height) {

+    var args = [];

+    args.push(["line", Math.round(left), Math.round(top)]);

+    args.push(["line", Math.round(left + width), Math.round(top)]);

+    args.push(["line", Math.round(left + width), Math.round(height + top)]);

+    args.push(["line", Math.round(left), Math.round(height + top)]);

+    createShape(ctx, args);

+    ctx.save();

+    ctx.clip();

+    renderBackgroundRepeat(ctx, image, backgroundPosition, bounds);

+    ctx.restore();

+  }

+

+  function renderBackgroundColor(ctx, backgroundBounds, bgcolor) {

+    renderRect(

+      ctx,

+      backgroundBounds.left,

+      backgroundBounds.top,

+      backgroundBounds.width,

+      backgroundBounds.height,

+      bgcolor

+      );

+  }

+

+  function renderBackgroundRepeating(el, bounds, ctx, image, imageIndex) {

+    var backgroundSize = Util.BackgroundSize(el, bounds, image, imageIndex),

+    backgroundPosition = Util.BackgroundPosition(el, bounds, image, imageIndex, backgroundSize),

+    backgroundRepeat = getCSS(el, "backgroundRepeat").split(",").map(Util.trimText);

+

+    image = resizeImage(image, backgroundSize);

+

+    backgroundRepeat = backgroundRepeat[imageIndex] || backgroundRepeat[0];

+

+    switch (backgroundRepeat) {

+      case "repeat-x":

+        backgroundRepeatShape(ctx, image, backgroundPosition, bounds,

+          bounds.left, bounds.top + backgroundPosition.top, 99999, image.height);

+        break;

+

+      case "repeat-y":

+        backgroundRepeatShape(ctx, image, backgroundPosition, bounds,

+          bounds.left + backgroundPosition.left, bounds.top, image.width, 99999);

+        break;

+

+      case "no-repeat":

+        backgroundRepeatShape(ctx, image, backgroundPosition, bounds,

+          bounds.left + backgroundPosition.left, bounds.top + backgroundPosition.top, image.width, image.height);

+        break;

+

+      default:

+        renderBackgroundRepeat(ctx, image, backgroundPosition, {

+          top: bounds.top,

+          left: bounds.left,

+          width: image.width,

+          height: image.height

+        });

+        break;

+    }

+  }

+

+  function renderBackgroundImage(element, bounds, ctx) {

+    var backgroundImage = getCSS(element, "backgroundImage"),

+    backgroundImages = Util.parseBackgroundImage(backgroundImage),

+    image,

+    imageIndex = backgroundImages.length;

+

+    while(imageIndex--) {

+      backgroundImage = backgroundImages[imageIndex];

+

+      if (!backgroundImage.args || backgroundImage.args.length === 0) {

+        continue;

+      }

+

+      var key = backgroundImage.method === 'url' ?

+      backgroundImage.args[0] :

+      backgroundImage.value;

+

+      image = loadImage(key);

+

+      // TODO add support for background-origin

+      if (image) {

+        renderBackgroundRepeating(element, bounds, ctx, image, imageIndex);

+      } else {

+        Util.log("html2canvas: Error loading background:", backgroundImage);

+      }

+    }

+  }

+

+  function resizeImage(image, bounds) {

+    if(image.width === bounds.width && image.height === bounds.height) {

+      return image;

+    }

+

+    var ctx, canvas = doc.createElement('canvas');

+    canvas.width = bounds.width;

+    canvas.height = bounds.height;

+    ctx = canvas.getContext("2d");

+    drawImage(ctx, image, 0, 0, image.width, image.height, 0, 0, bounds.width, bounds.height );

+    return canvas;

+  }

+

+  function setOpacity(ctx, element, parentStack) {

+    return ctx.setVariable("globalAlpha", getCSS(element, "opacity") * ((parentStack) ? parentStack.opacity : 1));

+  }

+

+  function removePx(str) {

+    return str.replace("px", "");

+  }

+

+  var transformRegExp = /(matrix)\((.+)\)/;

+

+  function getTransform(element, parentStack) {

+    var transform = getCSS(element, "transform") || getCSS(element, "-webkit-transform") || getCSS(element, "-moz-transform") || getCSS(element, "-ms-transform") || getCSS(element, "-o-transform");

+    var transformOrigin = getCSS(element, "transform-origin") || getCSS(element, "-webkit-transform-origin") || getCSS(element, "-moz-transform-origin") || getCSS(element, "-ms-transform-origin") || getCSS(element, "-o-transform-origin") || "0px 0px";

+

+    transformOrigin = transformOrigin.split(" ").map(removePx).map(Util.asFloat);

+

+    var matrix;

+    if (transform && transform !== "none") {

+      var match = transform.match(transformRegExp);

+      if (match) {

+        switch(match[1]) {

+          case "matrix":

+            matrix = match[2].split(",").map(Util.trimText).map(Util.asFloat);

+            break;

+        }

+      }

+    }

+

+    return {

+      origin: transformOrigin,

+      matrix: matrix

+    };

+  }

+

+  function createStack(element, parentStack, bounds, transform) {

+    var ctx = h2cRenderContext((!parentStack) ? documentWidth() : bounds.width , (!parentStack) ? documentHeight() : bounds.height),

+    stack = {

+      ctx: ctx,

+      opacity: setOpacity(ctx, element, parentStack),

+      cssPosition: getCSS(element, "position"),

+      borders: getBorderData(element),

+      transform: transform,

+      clip: (parentStack && parentStack.clip) ? Util.Extend( {}, parentStack.clip ) : null

+    };

+

+    setZ(element, stack, parentStack);

+

+    // TODO correct overflow for absolute content residing under a static position

+    if (options.useOverflow === true && /(hidden|scroll|auto)/.test(getCSS(element, "overflow")) === true && /(BODY)/i.test(element.nodeName) === false){

+      stack.clip = (stack.clip) ? clipBounds(stack.clip, bounds) : bounds;

+    }

+

+    return stack;

+  }

+

+  function getBackgroundBounds(borders, bounds, clip) {

+    var backgroundBounds = {

+      left: bounds.left + borders[3].width,

+      top: bounds.top + borders[0].width,

+      width: bounds.width - (borders[1].width + borders[3].width),

+      height: bounds.height - (borders[0].width + borders[2].width)

+    };

+

+    if (clip) {

+      backgroundBounds = clipBounds(backgroundBounds, clip);

+    }

+

+    return backgroundBounds;

+  }

+

+  function getBounds(element, transform) {

+    var bounds = (transform.matrix) ? Util.OffsetBounds(element) : Util.Bounds(element);

+    transform.origin[0] += bounds.left;

+    transform.origin[1] += bounds.top;

+    return bounds;

+  }

+

+  function renderElement(element, parentStack, pseudoElement, ignoreBackground) {

+    var transform = getTransform(element, parentStack),

+    bounds = getBounds(element, transform),

+    image,

+    stack = createStack(element, parentStack, bounds, transform),

+    borders = stack.borders,

+    ctx = stack.ctx,

+    backgroundBounds = getBackgroundBounds(borders, bounds, stack.clip),

+    borderData = parseBorders(element, bounds, borders),

+    backgroundColor = (ignoreElementsRegExp.test(element.nodeName)) ? "#efefef" : getCSS(element, "backgroundColor");

+

+

+    createShape(ctx, borderData.clip);

+

+    ctx.save();

+    ctx.clip();

+

+    if (backgroundBounds.height > 0 && backgroundBounds.width > 0 && !ignoreBackground) {

+      renderBackgroundColor(ctx, bounds, backgroundColor);

+      renderBackgroundImage(element, backgroundBounds, ctx);

+    } else if (ignoreBackground) {

+      stack.backgroundColor =  backgroundColor;

+    }

+

+    ctx.restore();

+

+    borderData.borders.forEach(function(border) {

+      renderBorders(ctx, border.args, border.color);

+    });

+

+    if (!pseudoElement) {

+      injectPseudoElements(element, stack);

+    }

+

+    switch(element.nodeName){

+      case "IMG":

+        if ((image = loadImage(element.getAttribute('src')))) {

+          renderImage(ctx, element, image, bounds, borders);

+        } else {

+          Util.log("html2canvas: Error loading <img>:" + element.getAttribute('src'));

+        }

+        break;

+      case "INPUT":

+        // TODO add all relevant type's, i.e. HTML5 new stuff

+        // todo add support for placeholder attribute for browsers which support it

+        if (/^(text|url|email|submit|button|reset)$/.test(element.type) && (element.value || element.placeholder || "").length > 0){

+          renderFormValue(element, bounds, stack);

+        }

+        break;

+      case "TEXTAREA":

+        if ((element.value || element.placeholder || "").length > 0){

+          renderFormValue(element, bounds, stack);

+        }

+        break;

+      case "SELECT":

+        if ((element.options||element.placeholder || "").length > 0){

+          renderFormValue(element, bounds, stack);

+        }

+        break;

+      case "LI":

+        renderListItem(element, stack, backgroundBounds);

+        break;

+      case "CANVAS":

+        renderImage(ctx, element, element, bounds, borders);

+        break;

+    }

+

+    return stack;

+  }

+

+  function isElementVisible(element) {

+    return (getCSS(element, 'display') !== "none" && getCSS(element, 'visibility') !== "hidden" && !element.hasAttribute("data-html2canvas-ignore"));

+  }

+

+  function parseElement (element, stack, pseudoElement) {

+    if (isElementVisible(element)) {

+      stack = renderElement(element, stack, pseudoElement, false) || stack;

+      if (!ignoreElementsRegExp.test(element.nodeName)) {

+        parseChildren(element, stack, pseudoElement);

+      }

+    }

+  }

+

+  function parseChildren(element, stack, pseudoElement) {

+    Util.Children(element).forEach(function(node) {

+      if (node.nodeType === node.ELEMENT_NODE) {

+        parseElement(node, stack, pseudoElement);

+      } else if (node.nodeType === node.TEXT_NODE) {

+        renderText(element, node, stack);

+      }

+    });

+  }

+

+  function init() {

+    var background = getCSS(document.documentElement, "backgroundColor"),

+      transparentBackground = (Util.isTransparent(background) && element === document.body),

+      stack = renderElement(element, null, false, transparentBackground);

+    parseChildren(element, stack);

+

+    if (transparentBackground) {

+      background = stack.backgroundColor;

+    }

+

+    body.removeChild(hidePseudoElements);

+    return {

+      backgroundColor: background,

+      stack: stack

+    };

+  }

+

+  return init();

+};

+

+function h2czContext(zindex) {

+  return {

+    zindex: zindex,

+    children: []

+  };

+}

+

+_html2canvas.Preload = function( options ) {

+

+  var images = {

+    numLoaded: 0,   // also failed are counted here

+    numFailed: 0,

+    numTotal: 0,

+    cleanupDone: false

+  },

+  pageOrigin,

+  Util = _html2canvas.Util,

+  methods,

+  i,

+  count = 0,

+  element = options.elements[0] || document.body,

+  doc = element.ownerDocument,

+  domImages = element.getElementsByTagName('img'), // Fetch images of the present element only

+  imgLen = domImages.length,

+  link = doc.createElement("a"),

+  supportCORS = (function( img ){

+    return (img.crossOrigin !== undefined);

+  })(new Image()),

+  timeoutTimer;

+

+  link.href = window.location.href;

+  pageOrigin  = link.protocol + link.host;

+

+  function isSameOrigin(url){

+    link.href = url;

+    link.href = link.href; // YES, BELIEVE IT OR NOT, that is required for IE9 - http://jsfiddle.net/niklasvh/2e48b/

+    var origin = link.protocol + link.host;

+    return (origin === pageOrigin);

+  }

+

+  function start(){

+    Util.log("html2canvas: start: images: " + images.numLoaded + " / " + images.numTotal + " (failed: " + images.numFailed + ")");

+    if (!images.firstRun && images.numLoaded >= images.numTotal){

+      Util.log("Finished loading images: # " + images.numTotal + " (failed: " + images.numFailed + ")");

+

+      if (typeof options.complete === "function"){

+        options.complete(images);

+      }

+

+    }

+  }

+

+  // TODO modify proxy to serve images with CORS enabled, where available

+  function proxyGetImage(url, img, imageObj){

+    var callback_name,

+    scriptUrl = options.proxy,

+    script;

+

+    link.href = url;

+    url = link.href; // work around for pages with base href="" set - WARNING: this may change the url

+

+    callback_name = 'html2canvas_' + (count++);

+    imageObj.callbackname = callback_name;

+

+    if (scriptUrl.indexOf("?") > -1) {

+      scriptUrl += "&";

+    } else {

+      scriptUrl += "?";

+    }

+    scriptUrl += 'url=' + encodeURIComponent(url) + '&callback=' + callback_name;

+    script = doc.createElement("script");

+

+    window[callback_name] = function(a){

+      if (a.substring(0,6) === "error:"){

+        imageObj.succeeded = false;

+        images.numLoaded++;

+        images.numFailed++;

+        start();

+      } else {

+        setImageLoadHandlers(img, imageObj);

+        img.src = a;

+      }

+      window[callback_name] = undefined; // to work with IE<9  // NOTE: that the undefined callback property-name still exists on the window object (for IE<9)

+      try {

+        delete window[callback_name];  // for all browser that support this

+      } catch(ex) {}

+      script.parentNode.removeChild(script);

+      script = null;

+      delete imageObj.script;

+      delete imageObj.callbackname;

+    };

+

+    script.setAttribute("type", "text/javascript");

+    script.setAttribute("src", scriptUrl);

+    imageObj.script = script;

+    window.document.body.appendChild(script);

+

+  }

+

+  function loadPseudoElement(element, type) {

+    var style = window.getComputedStyle(element, type),

+    content = style.content;

+    if (content.substr(0, 3) === 'url') {

+      methods.loadImage(_html2canvas.Util.parseBackgroundImage(content)[0].args[0]);

+    }

+    loadBackgroundImages(style.backgroundImage, element);

+  }

+

+  function loadPseudoElementImages(element) {

+    loadPseudoElement(element, ":before");

+    loadPseudoElement(element, ":after");

+  }

+

+  function loadGradientImage(backgroundImage, bounds) {

+    var img = _html2canvas.Generate.Gradient(backgroundImage, bounds);

+

+    if (img !== undefined){

+      images[backgroundImage] = {

+        img: img,

+        succeeded: true

+      };

+      images.numTotal++;

+      images.numLoaded++;

+      start();

+    }

+  }

+

+  function invalidBackgrounds(background_image) {

+    return (background_image && background_image.method && background_image.args && background_image.args.length > 0 );

+  }

+

+  function loadBackgroundImages(background_image, el) {

+    var bounds;

+

+    _html2canvas.Util.parseBackgroundImage(background_image).filter(invalidBackgrounds).forEach(function(background_image) {

+      if (background_image.method === 'url') {

+        methods.loadImage(background_image.args[0]);

+      } else if(background_image.method.match(/\-?gradient$/)) {

+        if(bounds === undefined) {

+          bounds = _html2canvas.Util.Bounds(el);

+        }

+        loadGradientImage(background_image.value, bounds);

+      }

+    });

+  }

+

+  function getImages (el) {

+    var elNodeType = false;

+

+    // Firefox fails with permission denied on pages with iframes

+    try {

+      Util.Children(el).forEach(getImages);

+    }

+    catch( e ) {}

+

+    try {

+      elNodeType = el.nodeType;

+    } catch (ex) {

+      elNodeType = false;

+      Util.log("html2canvas: failed to access some element's nodeType - Exception: " + ex.message);

+    }

+

+    if (elNodeType === 1 || elNodeType === undefined) {

+      loadPseudoElementImages(el);

+      try {

+        loadBackgroundImages(Util.getCSS(el, 'backgroundImage'), el);

+      } catch(e) {

+        Util.log("html2canvas: failed to get background-image - Exception: " + e.message);

+      }

+      loadBackgroundImages(el);

+    }

+  }

+

+  function setImageLoadHandlers(img, imageObj) {

+    img.onload = function() {

+      if ( imageObj.timer !== undefined ) {

+        // CORS succeeded

+        window.clearTimeout( imageObj.timer );

+      }

+

+      images.numLoaded++;

+      imageObj.succeeded = true;

+      img.onerror = img.onload = null;

+      start();

+    };

+    img.onerror = function() {

+      if (img.crossOrigin === "anonymous") {

+        // CORS failed

+        window.clearTimeout( imageObj.timer );

+

+        // let's try with proxy instead

+        if ( options.proxy ) {

+          var src = img.src;

+          img = new Image();

+          imageObj.img = img;

+          img.src = src;

+

+          proxyGetImage( img.src, img, imageObj );

+          return;

+        }

+      }

+

+      images.numLoaded++;

+      images.numFailed++;

+      imageObj.succeeded = false;

+      img.onerror = img.onload = null;

+      start();

+    };

+  }

+

+  methods = {

+    loadImage: function( src ) {

+      var img, imageObj;

+      if ( src && images[src] === undefined ) {

+        img = new Image();

+        if ( src.match(/data:image\/.*;base64,/i) ) {

+          img.src = src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, '');

+          imageObj = images[src] = {

+            img: img

+          };

+          images.numTotal++;

+          setImageLoadHandlers(img, imageObj);

+        } else if ( isSameOrigin( src ) || options.allowTaint ===  true ) {

+          imageObj = images[src] = {

+            img: img

+          };

+          images.numTotal++;

+          setImageLoadHandlers(img, imageObj);

+          img.src = src;

+        } else if ( supportCORS && !options.allowTaint && options.useCORS ) {

+          // attempt to load with CORS

+

+          img.crossOrigin = "anonymous";

+          imageObj = images[src] = {

+            img: img

+          };

+          images.numTotal++;

+          setImageLoadHandlers(img, imageObj);

+          img.src = src;

+        } else if ( options.proxy ) {

+          imageObj = images[src] = {

+            img: img

+          };

+          images.numTotal++;

+          proxyGetImage( src, img, imageObj );

+        }

+      }

+

+    },

+    cleanupDOM: function(cause) {

+      var img, src;

+      if (!images.cleanupDone) {

+        if (cause && typeof cause === "string") {

+          Util.log("html2canvas: Cleanup because: " + cause);

+        } else {

+          Util.log("html2canvas: Cleanup after timeout: " + options.timeout + " ms.");

+        }

+

+        for (src in images) {

+          if (images.hasOwnProperty(src)) {

+            img = images[src];

+            if (typeof img === "object" && img.callbackname && img.succeeded === undefined) {

+              // cancel proxy image request

+              window[img.callbackname] = undefined; // to work with IE<9  // NOTE: that the undefined callback property-name still exists on the window object (for IE<9)

+              try {

+                delete window[img.callbackname];  // for all browser that support this

+              } catch(ex) {}

+              if (img.script && img.script.parentNode) {

+                img.script.setAttribute("src", "about:blank");  // try to cancel running request

+                img.script.parentNode.removeChild(img.script);

+              }

+              images.numLoaded++;

+              images.numFailed++;

+              Util.log("html2canvas: Cleaned up failed img: '" + src + "' Steps: " + images.numLoaded + " / " + images.numTotal);

+            }

+          }

+        }

+

+        // cancel any pending requests

+        if(window.stop !== undefined) {

+          window.stop();

+        } else if(document.execCommand !== undefined) {

+          document.execCommand("Stop", false);

+        }

+        if (document.close !== undefined) {

+          document.close();

+        }

+        images.cleanupDone = true;

+        if (!(cause && typeof cause === "string")) {

+          start();

+        }

+      }

+    },

+

+    renderingDone: function() {

+      if (timeoutTimer) {

+        window.clearTimeout(timeoutTimer);

+      }

+    }

+  };

+

+  if (options.timeout > 0) {

+    timeoutTimer = window.setTimeout(methods.cleanupDOM, options.timeout);

+  }

+

+  Util.log('html2canvas: Preload starts: finding background-images');

+  images.firstRun = true;

+

+  getImages(element);

+

+  Util.log('html2canvas: Preload: Finding images');

+  // load <img> images

+  for (i = 0; i < imgLen; i+=1){

+    methods.loadImage( domImages[i].getAttribute( "src" ) );

+  }

+

+  images.firstRun = false;

+  Util.log('html2canvas: Preload: Done.');

+  if (images.numTotal === images.numLoaded) {

+    start();

+  }

+

+  return methods;

+};

+

+_html2canvas.Renderer = function(parseQueue, options){

+

+  // http://www.w3.org/TR/CSS21/zindex.html

+  function createRenderQueue(parseQueue) {

+    var queue = [],

+    rootContext;

+

+    rootContext = (function buildStackingContext(rootNode) {

+      var rootContext = {};

+      function insert(context, node, specialParent) {

+        var zi = (node.zIndex.zindex === 'auto') ? 0 : Number(node.zIndex.zindex),

+        contextForChildren = context, // the stacking context for children

+        isPositioned = node.zIndex.isPositioned,

+        isFloated = node.zIndex.isFloated,

+        stub = {node: node},

+        childrenDest = specialParent; // where children without z-index should be pushed into

+

+        if (node.zIndex.ownStacking) {

+          // '!' comes before numbers in sorted array

+          contextForChildren = stub.context = { '!': [{node:node, children: []}]};

+          childrenDest = undefined;

+        } else if (isPositioned || isFloated) {

+          childrenDest = stub.children = [];

+        }

+

+        if (zi === 0 && specialParent) {

+          specialParent.push(stub);

+        } else {

+          if (!context[zi]) { context[zi] = []; }

+          context[zi].push(stub);

+        }

+

+        node.zIndex.children.forEach(function(childNode) {

+          insert(contextForChildren, childNode, childrenDest);

+        });

+      }

+      insert(rootContext, rootNode);

+      return rootContext;

+    })(parseQueue);

+

+    function sortZ(context) {

+      Object.keys(context).sort().forEach(function(zi) {

+        var nonPositioned = [],

+        floated = [],

+        positioned = [],

+        list = [];

+

+        // positioned after static

+        context[zi].forEach(function(v) {

+          if (v.node.zIndex.isPositioned || v.node.zIndex.opacity < 1) {

+            // http://www.w3.org/TR/css3-color/#transparency

+            // non-positioned element with opactiy < 1 should be stacked as if it were a positioned element with ‘z-index: 0’ and ‘opacity: 1’.

+            positioned.push(v);

+          } else if (v.node.zIndex.isFloated) {

+            floated.push(v);

+          } else {

+            nonPositioned.push(v);

+          }

+        });

+

+        (function walk(arr) {

+          arr.forEach(function(v) {

+            list.push(v);

+            if (v.children) { walk(v.children); }

+          });

+        })(nonPositioned.concat(floated, positioned));

+

+        list.forEach(function(v) {

+          if (v.context) {

+            sortZ(v.context);

+          } else {

+            queue.push(v.node);

+          }

+        });

+      });

+    }

+

+    sortZ(rootContext);

+

+    return queue;

+  }

+

+  function getRenderer(rendererName) {

+    var renderer;

+

+    if (typeof options.renderer === "string" && _html2canvas.Renderer[rendererName] !== undefined) {

+      renderer = _html2canvas.Renderer[rendererName](options);

+    } else if (typeof rendererName === "function") {

+      renderer = rendererName(options);

+    } else {

+      throw new Error("Unknown renderer");

+    }

+

+    if ( typeof renderer !== "function" ) {

+      throw new Error("Invalid renderer defined");

+    }

+    return renderer;

+  }

+

+  return getRenderer(options.renderer)(parseQueue, options, document, createRenderQueue(parseQueue.stack), _html2canvas);

+};

+

+_html2canvas.Util.Support = function (options, doc) {

+

+  function supportSVGRendering() {

+    var img = new Image(),

+    canvas = doc.createElement("canvas"),

+    ctx = (canvas.getContext === undefined) ? false : canvas.getContext("2d");

+    if (ctx === false) {

+      return false;

+    }

+    canvas.width = canvas.height = 10;

+    img.src = [

+    "data:image/svg+xml,",

+    "<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'>",

+    "<foreignObject width='10' height='10'>",

+    "<div xmlns='http://www.w3.org/1999/xhtml' style='width:10;height:10;'>",

+    "sup",

+    "</div>",

+    "</foreignObject>",

+    "</svg>"

+    ].join("");

+    try {

+      ctx.drawImage(img, 0, 0);

+      canvas.toDataURL();

+    } catch(e) {

+      return false;

+    }

+    _html2canvas.Util.log('html2canvas: Parse: SVG powered rendering available');

+    return true;

+  }

+

+  // Test whether we can use ranges to measure bounding boxes

+  // Opera doesn't provide valid bounds.height/bottom even though it supports the method.

+

+  function supportRangeBounds() {

+    var r, testElement, rangeBounds, rangeHeight, support = false;

+

+    if (doc.createRange) {

+      r = doc.createRange();

+      if (r.getBoundingClientRect) {

+        testElement = doc.createElement('boundtest');

+        testElement.style.height = "123px";

+        testElement.style.display = "block";

+        doc.body.appendChild(testElement);

+

+        r.selectNode(testElement);

+        rangeBounds = r.getBoundingClientRect();

+        rangeHeight = rangeBounds.height;

+

+        if (rangeHeight === 123) {

+          support = true;

+        }

+        doc.body.removeChild(testElement);

+      }

+    }

+

+    return support;

+  }

+

+  return {

+    rangeBounds: supportRangeBounds(),

+    svgRendering: options.svgRendering && supportSVGRendering()

+  };

+};

+window.html2canvas = function(elements, opts) {

+  elements = (elements.length) ? elements : [elements];

+  var queue,

+  canvas,

+  options = {

+    // general

+    logging: false,

+    elements: elements,

+    background: "#fff",

+

+    // preload options

+    proxy: null,

+    timeout: 0,    // no timeout

+    useCORS: false, // try to load images as CORS (where available), before falling back to proxy

+    allowTaint: false, // whether to allow images to taint the canvas, won't need proxy if set to true

+

+    // parse options

+    svgRendering: false, // use svg powered rendering where available (FF11+)

+    ignoreElements: "IFRAME|OBJECT|PARAM",

+    useOverflow: true,

+    letterRendering: false,

+    chinese: false,

+

+    // render options

+

+    width: null,

+    height: null,

+    taintTest: true, // do a taint test with all images before applying to canvas

+    renderer: "Canvas"

+  };

+

+  options = _html2canvas.Util.Extend(opts, options);

+

+  _html2canvas.logging = options.logging;

+  options.complete = function( images ) {

+

+    if (typeof options.onpreloaded === "function") {

+      if ( options.onpreloaded( images ) === false ) {

+        return;

+      }

+    }

+    queue = _html2canvas.Parse( images, options );

+

+    if (typeof options.onparsed === "function") {

+      if ( options.onparsed( queue ) === false ) {

+        return;

+      }

+    }

+

+    canvas = _html2canvas.Renderer( queue, options );

+

+    if (typeof options.onrendered === "function") {

+      options.onrendered( canvas );

+    }

+

+

+  };

+

+  // for pages without images, we still want this to be async, i.e. return methods before executing

+  window.setTimeout( function(){

+    _html2canvas.Preload( options );

+  }, 0 );

+

+  return {

+    render: function( queue, opts ) {

+      return _html2canvas.Renderer( queue, _html2canvas.Util.Extend(opts, options) );

+    },

+    parse: function( images, opts ) {

+      return _html2canvas.Parse( images, _html2canvas.Util.Extend(opts, options) );

+    },

+    preload: function( opts ) {

+      return _html2canvas.Preload( _html2canvas.Util.Extend(opts, options) );

+    },

+    log: _html2canvas.Util.log

+  };

+};

+

+window.html2canvas.log = _html2canvas.Util.log; // for renderers

+window.html2canvas.Renderer = {

+  Canvas: undefined // We are assuming this will be used

+};

+_html2canvas.Renderer.Canvas = function(options) {

+  options = options || {};

+

+  var doc = document,

+  safeImages = [],

+  testCanvas = document.createElement("canvas"),

+  testctx = testCanvas.getContext("2d"),

+  Util = _html2canvas.Util,

+  canvas = options.canvas || doc.createElement('canvas');

+

+  function createShape(ctx, args) {

+    ctx.beginPath();

+    args.forEach(function(arg) {

+      ctx[arg.name].apply(ctx, arg['arguments']);

+    });

+    ctx.closePath();

+  }

+

+  function safeImage(item) {

+    if (safeImages.indexOf(item['arguments'][0].src ) === -1) {

+      testctx.drawImage(item['arguments'][0], 0, 0);

+      try {

+        testctx.getImageData(0, 0, 1, 1);

+      } catch(e) {

+        testCanvas = doc.createElement("canvas");

+        testctx = testCanvas.getContext("2d");

+        return false;

+      }

+      safeImages.push(item['arguments'][0].src);

+    }

+    return true;

+  }

+

+  function renderItem(ctx, item) {

+    switch(item.type){

+      case "variable":

+        ctx[item.name] = item['arguments'];

+        break;

+      case "function":

+        switch(item.name) {

+          case "createPattern":

+            if (item['arguments'][0].width > 0 && item['arguments'][0].height > 0) {

+              try {

+                ctx.fillStyle = ctx.createPattern(item['arguments'][0], "repeat");

+              }

+              catch(e) {

+                Util.log("html2canvas: Renderer: Error creating pattern", e.message);

+              }

+            }

+            break;

+          case "drawShape":

+            createShape(ctx, item['arguments']);

+            break;

+          case "drawImage":

+            if (item['arguments'][8] > 0 && item['arguments'][7] > 0) {

+              if (!options.taintTest || (options.taintTest && safeImage(item))) {

+                ctx.drawImage.apply( ctx, item['arguments'] );

+              }

+            }

+            break;

+          default:

+            ctx[item.name].apply(ctx, item['arguments']);

+        }

+        break;

+    }

+  }

+

+  return function(parsedData, options, document, queue, _html2canvas) {

+    var ctx = canvas.getContext("2d"),

+    newCanvas,

+    bounds,

+    fstyle,

+    zStack = parsedData.stack;

+

+    canvas.width = canvas.style.width =  options.width || zStack.ctx.width;

+    canvas.height = canvas.style.height = options.height || zStack.ctx.height;

+

+    fstyle = ctx.fillStyle;

+    ctx.fillStyle = (Util.isTransparent(zStack.backgroundColor) && options.background !== undefined) ? options.background : parsedData.backgroundColor;

+    ctx.fillRect(0, 0, canvas.width, canvas.height);

+    ctx.fillStyle = fstyle;

+

+    queue.forEach(function(storageContext) {

+      // set common settings for canvas

+      ctx.textBaseline = "bottom";

+      ctx.save();

+

+      if (storageContext.transform.matrix) {

+        ctx.translate(storageContext.transform.origin[0], storageContext.transform.origin[1]);

+        ctx.transform.apply(ctx, storageContext.transform.matrix);

+        ctx.translate(-storageContext.transform.origin[0], -storageContext.transform.origin[1]);

+      }

+

+      if (storageContext.clip){

+        ctx.beginPath();

+        ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height);

+        ctx.clip();

+      }

+

+      if (storageContext.ctx.storage) {

+        storageContext.ctx.storage.forEach(function(item) {

+          renderItem(ctx, item);

+        });

+      }

+

+      ctx.restore();

+    });

+

+    Util.log("html2canvas: Renderer: Canvas renderer done - returning canvas obj");

+

+    if (options.elements.length === 1) {

+      if (typeof options.elements[0] === "object" && options.elements[0].nodeName !== "BODY") {

+        // crop image to the bounds of selected (single) element

+        bounds = _html2canvas.Util.Bounds(options.elements[0]);

+        newCanvas = document.createElement('canvas');

+        newCanvas.width = Math.ceil(bounds.width);

+        newCanvas.height = Math.ceil(bounds.height);

+        ctx = newCanvas.getContext("2d");

+

+        ctx.drawImage(canvas, bounds.left, bounds.top, bounds.width, bounds.height, 0, 0, bounds.width, bounds.height);

+        canvas = null;

+        return newCanvas;

+      }

+    }

+

+    return canvas;

+  };

+};

+})(window,document);
\ No newline at end of file
diff --git a/htdocs/Libs/JQuery/jquery-2.2.3.min.js b/htdocs/Libs/JQuery/jquery-2.2.3.min.js
new file mode 100644
index 0000000..b8c4187
--- /dev/null
+++ b/htdocs/Libs/JQuery/jquery-2.2.3.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v2.2.3 | (c) jQuery Foundation | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="2.2.3",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isPlainObject:function(a){var b;if("object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype||{},"isPrototypeOf"))return!1;for(b in a);return void 0===b||k.call(a,b)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=d.createElement("script"),b.text=a,d.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:h.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(d=e.call(arguments,2),f=function(){return a.apply(b||this,d.concat(e.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=la(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=ma(b);function pa(){}pa.prototype=d.filters=d.pseudos,d.setFilters=new pa,g=fa.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=R.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=S.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(Q," ")}),h=h.slice(c.length));for(g in d.filter)!(e=W[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fa.error(a):z(a,i).slice(0)};function qa(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return h.call(b,a)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&f.parentNode&&(this.length=1,this[0]=f),this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?void 0!==c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?h.call(n(a),this[0]):h.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||n.uniqueSort(e),D.test(a)&&e.reverse()),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){n.each(b,function(b,c){n.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==n.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return n.each(arguments,function(a,b){var c;while((c=n.inArray(b,f,c))>-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.removeEventListener("DOMContentLoaded",J),a.removeEventListener("load",J),n.ready()}n.ready.promise=function(b){return I||(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(n.ready):(d.addEventListener("DOMContentLoaded",J),a.addEventListener("load",J))),I.promise(b)},n.ready.promise();var K=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)K(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},L=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function M(){this.expando=n.expando+M.uid++}M.uid=1,M.prototype={register:function(a,b){var c=b||{};return a.nodeType?a[this.expando]=c:Object.defineProperty(a,this.expando,{value:c,writable:!0,configurable:!0}),a[this.expando]},cache:function(a){if(!L(a))return{};var b=a[this.expando];return b||(b={},L(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[b]=c;else for(d in b)e[d]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=a[this.expando];if(void 0!==f){if(void 0===b)this.register(a);else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in f?d=[b,e]:(d=e,d=d in f?[d]:d.match(G)||[])),c=d.length;while(c--)delete f[d[c]]}(void 0===b||n.isEmptyObject(f))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!n.isEmptyObject(b)}};var N=new M,O=new M,P=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Q=/[A-Z]/g;function R(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Q,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:P.test(c)?n.parseJSON(c):c;
+}catch(e){}O.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return O.hasData(a)||N.hasData(a)},data:function(a,b,c){return O.access(a,b,c)},removeData:function(a,b){O.remove(a,b)},_data:function(a,b,c){return N.access(a,b,c)},_removeData:function(a,b){N.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=O.get(f),1===f.nodeType&&!N.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),R(f,d,e[d])));N.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){O.set(this,a)}):K(this,function(b){var c,d;if(f&&void 0===b){if(c=O.get(f,a)||O.get(f,a.replace(Q,"-$&").toLowerCase()),void 0!==c)return c;if(d=n.camelCase(a),c=O.get(f,d),void 0!==c)return c;if(c=R(f,d,void 0),void 0!==c)return c}else d=n.camelCase(a),this.each(function(){var c=O.get(this,d);O.set(this,d,b),a.indexOf("-")>-1&&void 0!==c&&O.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){O.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=N.get(a,b),c&&(!d||n.isArray(c)?d=N.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return N.get(a,c)||N.access(a,c,{empty:n.Callbacks("once memory").add(function(){N.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=N.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),U=["Top","Right","Bottom","Left"],V=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)};function W(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return n.css(a,b,"")},i=h(),j=c&&c[3]||(n.cssNumber[b]?"":"px"),k=(n.cssNumber[b]||"px"!==j&&+i)&&T.exec(n.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,n.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var X=/^(?:checkbox|radio)$/i,Y=/<([\w:-]+)/,Z=/^$|\/(?:java|ecma)script/i,$={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};$.optgroup=$.option,$.tbody=$.tfoot=$.colgroup=$.caption=$.thead,$.th=$.td;function _(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function aa(a,b){for(var c=0,d=a.length;d>c;c++)N.set(a[c],"globalEval",!b||N.get(b[c],"globalEval"))}var ba=/<|&#?\w+;/;function ca(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],o=0,p=a.length;p>o;o++)if(f=a[o],f||0===f)if("object"===n.type(f))n.merge(m,f.nodeType?[f]:f);else if(ba.test(f)){g=g||l.appendChild(b.createElement("div")),h=(Y.exec(f)||["",""])[1].toLowerCase(),i=$[h]||$._default,g.innerHTML=i[1]+n.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;n.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",o=0;while(f=m[o++])if(d&&n.inArray(f,d)>-1)e&&e.push(f);else if(j=n.contains(f.ownerDocument,f),g=_(l.appendChild(f),"script"),j&&aa(g),c){k=0;while(f=g[k++])Z.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var da=/^key/,ea=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,fa=/^([^.]*)(?:\.(.+)|)/;function ga(){return!0}function ha(){return!1}function ia(){try{return d.activeElement}catch(a){}}function ja(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ja(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ha;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return"undefined"!=typeof n&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(G)||[""],j=b.length;while(j--)h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.hasData(a)&&N.get(a);if(r&&(i=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&N.remove(a,"handle events")}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(N.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!==this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget detail eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,e,f,g=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||d,e=c.documentElement,f=c.body,a.pageX=b.clientX+(e&&e.scrollLeft||f&&f.scrollLeft||0)-(e&&e.clientLeft||f&&f.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||f&&f.scrollTop||0)-(e&&e.clientTop||f&&f.clientTop||0)),a.which||void 0===g||(a.which=1&g?1:2&g?3:4&g?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,e,f=a.type,g=a,h=this.fixHooks[f];h||(this.fixHooks[f]=h=ea.test(f)?this.mouseHooks:da.test(f)?this.keyHooks:{}),e=h.props?this.props.concat(h.props):this.props,a=new n.Event(g),b=e.length;while(b--)c=e[b],a[c]=g[c];return a.target||(a.target=d),3===a.target.nodeType&&(a.target=a.target.parentNode),h.filter?h.filter(a,g):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==ia()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===ia()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ga:ha):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={constructor:n.Event,isDefaultPrevented:ha,isPropagationStopped:ha,isImmediatePropagationStopped:ha,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ga,a&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ga,a&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ga,a&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||n.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),n.fn.extend({on:function(a,b,c,d){return ja(this,a,b,c,d)},one:function(a,b,c,d){return ja(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=ha),this.each(function(){n.event.remove(this,a,c,b)})}});var ka=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,la=/<script|<style|<link/i,ma=/checked\s*(?:[^=]|=\s*.checked.)/i,na=/^true\/(.*)/,oa=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function pa(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function qa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function ra(a){var b=na.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function sa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(N.hasData(a)&&(f=N.access(a),g=N.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}O.hasData(a)&&(h=O.access(a),i=n.extend({},h),O.set(b,i))}}function ta(a,b){var c=b.nodeName.toLowerCase();"input"===c&&X.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function ua(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&ma.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),ua(f,b,c,d)});if(o&&(e=ca(b,a[0].ownerDocument,!1,a,d),g=e.firstChild,1===e.childNodes.length&&(e=g),g||d)){for(h=n.map(_(e,"script"),qa),i=h.length;o>m;m++)j=e,m!==p&&(j=n.clone(j,!0,!0),i&&n.merge(h,_(j,"script"))),c.call(a[m],j,m);if(i)for(k=h[h.length-1].ownerDocument,n.map(h,ra),m=0;i>m;m++)j=h[m],Z.test(j.type||"")&&!N.access(j,"globalEval")&&n.contains(k,j)&&(j.src?n._evalUrl&&n._evalUrl(j.src):n.globalEval(j.textContent.replace(oa,"")))}return a}function va(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(_(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&aa(_(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(ka,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=_(h),f=_(a),d=0,e=f.length;e>d;d++)ta(f[d],g[d]);if(b)if(c)for(f=f||_(a),g=g||_(h),d=0,e=f.length;e>d;d++)sa(f[d],g[d]);else sa(a,h);return g=_(h,"script"),g.length>0&&aa(g,!i&&_(a,"script")),h},cleanData:function(a){for(var b,c,d,e=n.event.special,f=0;void 0!==(c=a[f]);f++)if(L(c)){if(b=c[N.expando]){if(b.events)for(d in b.events)e[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);c[N.expando]=void 0}c[O.expando]&&(c[O.expando]=void 0)}}}),n.fn.extend({domManip:ua,detach:function(a){return va(this,a,!0)},remove:function(a){return va(this,a)},text:function(a){return K(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.appendChild(a)}})},prepend:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(_(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return K(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!la.test(a)&&!$[(Y.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(_(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return ua(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(_(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),f=e.length-1,h=0;f>=h;h++)c=h===f?this:this.clone(!0),n(e[h])[b](c),g.apply(d,c.get());return this.pushStack(d)}});var wa,xa={HTML:"block",BODY:"block"};function ya(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function za(a){var b=d,c=xa[a];return c||(c=ya(a,b),"none"!==c&&c||(wa=(wa||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=wa[0].contentDocument,b.write(),b.close(),c=ya(a,b),wa.detach()),xa[a]=c),c}var Aa=/^margin/,Ba=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ca=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)},Da=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},Ea=d.documentElement;!function(){var b,c,e,f,g=d.createElement("div"),h=d.createElement("div");if(h.style){h.style.backgroundClip="content-box",h.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===h.style.backgroundClip,g.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",g.appendChild(h);function i(){h.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",h.innerHTML="",Ea.appendChild(g);var d=a.getComputedStyle(h);b="1%"!==d.top,f="2px"===d.marginLeft,c="4px"===d.width,h.style.marginRight="50%",e="4px"===d.marginRight,Ea.removeChild(g)}n.extend(l,{pixelPosition:function(){return i(),b},boxSizingReliable:function(){return null==c&&i(),c},pixelMarginRight:function(){return null==c&&i(),e},reliableMarginLeft:function(){return null==c&&i(),f},reliableMarginRight:function(){var b,c=h.appendChild(d.createElement("div"));return c.style.cssText=h.style.cssText="-webkit-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",h.style.width="1px",Ea.appendChild(g),b=!parseFloat(a.getComputedStyle(c).marginRight),Ea.removeChild(g),h.removeChild(c),b}})}}();function Fa(a,b,c){var d,e,f,g,h=a.style;return c=c||Ca(a),g=c?c.getPropertyValue(b)||c[b]:void 0,""!==g&&void 0!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),c&&!l.pixelMarginRight()&&Ba.test(g)&&Aa.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f),void 0!==g?g+"":g}function Ga(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Ha=/^(none|table(?!-c[ea]).+)/,Ia={position:"absolute",visibility:"hidden",display:"block"},Ja={letterSpacing:"0",fontWeight:"400"},Ka=["Webkit","O","Moz","ms"],La=d.createElement("div").style;function Ma(a){if(a in La)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ka.length;while(c--)if(a=Ka[c]+b,a in La)return a}function Na(a,b,c){var d=T.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Oa(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+U[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+U[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+U[f]+"Width",!0,e))):(g+=n.css(a,"padding"+U[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+U[f]+"Width",!0,e)));return g}function Pa(b,c,e){var f=!0,g="width"===c?b.offsetWidth:b.offsetHeight,h=Ca(b),i="border-box"===n.css(b,"boxSizing",!1,h);if(d.msFullscreenElement&&a.top!==a&&b.getClientRects().length&&(g=Math.round(100*b.getBoundingClientRect()[c])),0>=g||null==g){if(g=Fa(b,c,h),(0>g||null==g)&&(g=b.style[c]),Ba.test(g))return g;f=i&&(l.boxSizingReliable()||g===b.style[c]),g=parseFloat(g)||0}return g+Oa(b,c,e||(i?"border":"content"),f,h)+"px"}function Qa(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=N.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&V(d)&&(f[g]=N.access(d,"olddisplay",za(d.nodeName)))):(e=V(d),"none"===c&&e||N.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Fa(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Ma(h)||h),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=T.exec(c))&&e[1]&&(c=W(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(n.cssNumber[h]?"":"px")),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Ma(h)||h),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Fa(a,b,d)),"normal"===e&&b in Ja&&(e=Ja[b]),""===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?Ha.test(n.css(a,"display"))&&0===a.offsetWidth?Da(a,Ia,function(){return Pa(a,b,d)}):Pa(a,b,d):void 0},set:function(a,c,d){var e,f=d&&Ca(a),g=d&&Oa(a,b,d,"border-box"===n.css(a,"boxSizing",!1,f),f);return g&&(e=T.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=n.css(a,b)),Na(a,c,g)}}}),n.cssHooks.marginLeft=Ga(l.reliableMarginLeft,function(a,b){return b?(parseFloat(Fa(a,"marginLeft"))||a.getBoundingClientRect().left-Da(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px":void 0}),n.cssHooks.marginRight=Ga(l.reliableMarginRight,function(a,b){return b?Da(a,{display:"inline-block"},Fa,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+U[d]+b]=f[d]||f[d-2]||f[0];return e}},Aa.test(a)||(n.cssHooks[a+b].set=Na)}),n.fn.extend({css:function(a,b){return K(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Ca(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Qa(this,!0)},hide:function(){return Qa(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){V(this)?n(this).show():n(this).hide()})}});function Ra(a,b,c,d,e){return new Ra.prototype.init(a,b,c,d,e)}n.Tween=Ra,Ra.prototype={constructor:Ra,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||n.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Ra.propHooks[this.prop];return a&&a.get?a.get(this):Ra.propHooks._default.get(this)},run:function(a){var b,c=Ra.propHooks[this.prop];return this.options.duration?this.pos=b=n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Ra.propHooks._default.set(this),this}},Ra.prototype.init.prototype=Ra.prototype,Ra.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[n.cssProps[a.prop]]&&!n.cssHooks[a.prop]?a.elem[a.prop]=a.now:n.style(a.elem,a.prop,a.now+a.unit)}}},Ra.propHooks.scrollTop=Ra.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},n.fx=Ra.prototype.init,n.fx.step={};var Sa,Ta,Ua=/^(?:toggle|show|hide)$/,Va=/queueHooks$/;function Wa(){return a.setTimeout(function(){Sa=void 0}),Sa=n.now()}function Xa(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=U[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ya(a,b,c){for(var d,e=(_a.tweeners[b]||[]).concat(_a.tweeners["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Za(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&V(a),q=N.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?N.get(a,"olddisplay")||za(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Ua.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?za(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=N.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;N.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ya(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function $a(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function _a(a,b,c){var d,e,f=0,g=_a.prefilters.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Sa||Wa(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{},easing:n.easing._default},c),originalProperties:b,originalOptions:c,startTime:Sa||Wa(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for($a(k,j.opts.specialEasing);g>f;f++)if(d=_a.prefilters[f].call(j,a,k,j.opts))return n.isFunction(d.stop)&&(n._queueHooks(j.elem,j.opts.queue).stop=n.proxy(d.stop,d)),d;return n.map(k,Ya,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(_a,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return W(c.elem,a,T.exec(b),c),c}]},tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.match(G);for(var c,d=0,e=a.length;e>d;d++)c=a[d],_a.tweeners[c]=_a.tweeners[c]||[],_a.tweeners[c].unshift(b)},prefilters:[Za],prefilter:function(a,b){b?_a.prefilters.unshift(a):_a.prefilters.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,null!=d.queue&&d.queue!==!0||(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(V).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=_a(this,n.extend({},a),f);(e||N.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=N.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Va.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=N.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Xa(b,!0),a,d,e)}}),n.each({slideDown:Xa("show"),slideUp:Xa("hide"),slideToggle:Xa("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(Sa=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),Sa=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Ta||(Ta=a.setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){a.clearInterval(Ta),Ta=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(b,c){return b=n.fx?n.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",l.checkOn=""!==a.value,l.optSelected=c.selected,b.disabled=!0,l.optDisabled=!c.disabled,a=d.createElement("input"),a.value="t",a.type="radio",l.radioValue="t"===a.value}();var ab,bb=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return K(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),e=n.attrHooks[b]||(n.expr.match.bool.test(b)?ab:void 0)),void 0!==c?null===c?void n.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=n.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(G);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)}}),ab={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=bb[b]||n.find.attr;bb[b]=function(a,b,d){var e,f;return d||(f=bb[b],bb[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,bb[b]=f),e}});var cb=/^(?:input|select|textarea|button)$/i,db=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return K(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&n.isXMLDoc(a)||(b=n.propFix[b]||b,
+e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):cb.test(a.nodeName)||db.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var eb=/[\t\r\n\f]/g;function fb(a){return a.getAttribute&&a.getAttribute("class")||""}n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,fb(this)))});if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=fb(c),d=1===c.nodeType&&(" "+e+" ").replace(eb," ")){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=n.trim(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,fb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=fb(c),d=1===c.nodeType&&(" "+e+" ").replace(eb," ")){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=n.trim(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):n.isFunction(a)?this.each(function(c){n(this).toggleClass(a.call(this,c,fb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=n(this),f=a.match(G)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=fb(this),b&&N.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":N.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+fb(c)+" ").replace(eb," ").indexOf(b)>-1)return!0;return!1}});var gb=/\r/g,hb=/[\x20\t\r\n\f]+/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(gb,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a)).replace(hb," ")}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],(c.selected||i===e)&&(l.optDisabled?!c.disabled:null===c.getAttribute("disabled"))&&(!c.parentNode.disabled||!n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(n.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>-1:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var ib=/^(?:focusinfocus|focusoutblur)$/;n.extend(n.event,{trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!ib.test(q+n.event.triggered)&&(q.indexOf(".")>-1&&(r=q.split("."),q=r.shift(),r.sort()),l=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},f||!o.trigger||o.trigger.apply(e,c)!==!1)){if(!f&&!o.noBubble&&!n.isWindow(e)){for(j=o.delegateType||q,ib.test(j+q)||(h=h.parentNode);h;h=h.parentNode)p.push(h),i=h;i===(e.ownerDocument||d)&&p.push(i.defaultView||i.parentWindow||a)}g=0;while((h=p[g++])&&!b.isPropagationStopped())b.type=g>1?j:o.bindType||q,m=(N.get(h,"events")||{})[b.type]&&N.get(h,"handle"),m&&m.apply(h,c),m=l&&h[l],m&&m.apply&&L(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=q,f||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!L(e)||l&&n.isFunction(e[q])&&!n.isWindow(e)&&(i=e[l],i&&(e[l]=null),n.event.triggered=q,e[q](),n.event.triggered=void 0,i&&(e[l]=i)),b.result}},simulate:function(a,b,c){var d=n.extend(new n.Event,c,{type:a,isSimulated:!0});n.event.trigger(d,null,b),d.isDefaultPrevented()&&c.preventDefault()}}),n.fn.extend({trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}}),n.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(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),l.focusin="onfocusin"in a,l.focusin||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a))};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=N.access(d,b);e||d.addEventListener(a,c,!0),N.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=N.access(d,b)-1;e?N.access(d,b,e):(d.removeEventListener(a,c,!0),N.remove(d,b))}}});var jb=a.location,kb=n.now(),lb=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||n.error("Invalid XML: "+b),c};var mb=/#.*$/,nb=/([?&])_=[^&]*/,ob=/^(.*?):[ \t]*([^\r\n]*)$/gm,pb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,qb=/^(?:GET|HEAD)$/,rb=/^\/\//,sb={},tb={},ub="*/".concat("*"),vb=d.createElement("a");vb.href=jb.href;function wb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(G)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function xb(a,b,c,d){var e={},f=a===tb;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function yb(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function zb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Ab(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:jb.href,type:"GET",isLocal:pb.test(jb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":ub,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?yb(yb(a,n.ajaxSettings),b):yb(n.ajaxSettings,a)},ajaxPrefilter:wb(sb),ajaxTransport:wb(tb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m=n.ajaxSetup({},c),o=m.context||m,p=m.context&&(o.nodeType||o.jquery)?n(o):n.event,q=n.Deferred(),r=n.Callbacks("once memory"),s=m.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,getResponseHeader:function(a){var b;if(2===v){if(!h){h={};while(b=ob.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===v?g:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return v||(a=u[c]=u[c]||a,t[a]=b),this},overrideMimeType:function(a){return v||(m.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>v)for(b in a)s[b]=[s[b],a[b]];else x.always(a[x.status]);return this},abort:function(a){var b=a||w;return e&&e.abort(b),z(0,b),this}};if(q.promise(x).complete=r.add,x.success=x.done,x.error=x.fail,m.url=((b||m.url||jb.href)+"").replace(mb,"").replace(rb,jb.protocol+"//"),m.type=c.method||c.type||m.method||m.type,m.dataTypes=n.trim(m.dataType||"*").toLowerCase().match(G)||[""],null==m.crossDomain){j=d.createElement("a");try{j.href=m.url,j.href=j.href,m.crossDomain=vb.protocol+"//"+vb.host!=j.protocol+"//"+j.host}catch(y){m.crossDomain=!0}}if(m.data&&m.processData&&"string"!=typeof m.data&&(m.data=n.param(m.data,m.traditional)),xb(sb,m,c,x),2===v)return x;k=n.event&&m.global,k&&0===n.active++&&n.event.trigger("ajaxStart"),m.type=m.type.toUpperCase(),m.hasContent=!qb.test(m.type),f=m.url,m.hasContent||(m.data&&(f=m.url+=(lb.test(f)?"&":"?")+m.data,delete m.data),m.cache===!1&&(m.url=nb.test(f)?f.replace(nb,"$1_="+kb++):f+(lb.test(f)?"&":"?")+"_="+kb++)),m.ifModified&&(n.lastModified[f]&&x.setRequestHeader("If-Modified-Since",n.lastModified[f]),n.etag[f]&&x.setRequestHeader("If-None-Match",n.etag[f])),(m.data&&m.hasContent&&m.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",m.contentType),x.setRequestHeader("Accept",m.dataTypes[0]&&m.accepts[m.dataTypes[0]]?m.accepts[m.dataTypes[0]]+("*"!==m.dataTypes[0]?", "+ub+"; q=0.01":""):m.accepts["*"]);for(l in m.headers)x.setRequestHeader(l,m.headers[l]);if(m.beforeSend&&(m.beforeSend.call(o,x,m)===!1||2===v))return x.abort();w="abort";for(l in{success:1,error:1,complete:1})x[l](m[l]);if(e=xb(tb,m,c,x)){if(x.readyState=1,k&&p.trigger("ajaxSend",[x,m]),2===v)return x;m.async&&m.timeout>0&&(i=a.setTimeout(function(){x.abort("timeout")},m.timeout));try{v=1,e.send(t,z)}catch(y){if(!(2>v))throw y;z(-1,y)}}else z(-1,"No Transport");function z(b,c,d,h){var j,l,t,u,w,y=c;2!==v&&(v=2,i&&a.clearTimeout(i),e=void 0,g=h||"",x.readyState=b>0?4:0,j=b>=200&&300>b||304===b,d&&(u=zb(m,x,d)),u=Ab(m,u,x,j),j?(m.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(n.lastModified[f]=w),w=x.getResponseHeader("etag"),w&&(n.etag[f]=w)),204===b||"HEAD"===m.type?y="nocontent":304===b?y="notmodified":(y=u.state,l=u.data,t=u.error,j=!t)):(t=y,!b&&y||(y="error",0>b&&(b=0))),x.status=b,x.statusText=(c||y)+"",j?q.resolveWith(o,[l,y,x]):q.rejectWith(o,[x,y,t]),x.statusCode(s),s=void 0,k&&p.trigger(j?"ajaxSuccess":"ajaxError",[x,m,j?l:t]),r.fireWith(o,[x,y]),k&&(p.trigger("ajaxComplete",[x,m]),--n.active||n.event.trigger("ajaxStop")))}return x},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax(n.extend({url:a,type:b,dataType:e,data:c,success:d},n.isPlainObject(a)&&a))}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return n.isFunction(a)?this.each(function(b){n(this).wrapInner(a.call(this,b))}):this.each(function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return!n.expr.filters.visible(a)},n.expr.filters.visible=function(a){return a.offsetWidth>0||a.offsetHeight>0||a.getClientRects().length>0};var Bb=/%20/g,Cb=/\[\]$/,Db=/\r?\n/g,Eb=/^(?:submit|button|image|reset|file)$/i,Fb=/^(?:input|select|textarea|keygen)/i;function Gb(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||Cb.test(a)?d(a,e):Gb(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Gb(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Gb(c,a[c],b,e);return d.join("&").replace(Bb,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&Fb.test(this.nodeName)&&!Eb.test(a)&&(this.checked||!X.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(Db,"\r\n")}}):{name:b.name,value:c.replace(Db,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Hb={0:200,1223:204},Ib=n.ajaxSettings.xhr();l.cors=!!Ib&&"withCredentials"in Ib,l.ajax=Ib=!!Ib,n.ajaxTransport(function(b){var c,d;return l.cors||Ib&&!b.crossDomain?{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Hb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=n("<script>").prop({charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&f("error"===a.type?404:200,a.type)}),d.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Jb=[],Kb=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Jb.pop()||n.expando+"_"+kb++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Kb.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Kb.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Kb,"$1"+e):b.jsonp!==!1&&(b.url+=(lb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?n(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Jb.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||d;var e=x.exec(a),f=!c&&[];return e?[b.createElement(e[1])]:(e=ca([a],b,f),f&&f.length&&n(f).remove(),n.merge([],e.childNodes))};var Lb=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Lb)return Lb.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};function Mb(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,n.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(e=d.getBoundingClientRect(),c=Mb(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0),d.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Ea})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c="pageYOffset"===b;n.fn[a]=function(d){return K(this,function(a,d,e){var f=Mb(a);return void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Ga(l.pixelPosition,function(a,c){return c?(c=Fa(a,b),Ba.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return K(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)},size:function(){return this.length}}),n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Nb=a.jQuery,Ob=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Ob),b&&a.jQuery===n&&(a.jQuery=Nb),n},b||(a.jQuery=a.$=n),n});
diff --git a/htdocs/Libs/JQuery/jquery.svg.js b/htdocs/Libs/JQuery/jquery.svg.js
new file mode 100644
index 0000000..aa972d6
--- /dev/null
+++ b/htdocs/Libs/JQuery/jquery.svg.js
@@ -0,0 +1,12 @@
+;(function ($) {

+    "use strict";

+    $.fn.createSVGNode = function (name, attrs) {

+        var elName = (name !== undefined && typeof name === "string") ? name : "svg";

+        var elAttrs = (attrs !== undefined && attrs instanceof Object) ? attrs : ((name instanceof Object) ? name : {});

+        var el = document.createElementNS("http://www.w3.org/2000/svg", elName);

+        for (var attr in elAttrs)

+            if (elAttrs.hasOwnProperty(attr))

+                el.setAttribute(attr, elAttrs[attr]);

+        return $(this.get(0).appendChild(el));

+    };

+}(jQuery));

diff --git a/htdocs/Libs/JQueryUI/images/ui-bg_glass_55_fbf9ee_1x400.png b/htdocs/Libs/JQueryUI/images/ui-bg_glass_55_fbf9ee_1x400.png
new file mode 100644
index 0000000..8d9dd5f
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/images/ui-bg_glass_55_fbf9ee_1x400.png
Binary files differ
diff --git a/htdocs/Libs/JQueryUI/images/ui-bg_glass_65_ffffff_1x400.png b/htdocs/Libs/JQueryUI/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100644
index 0000000..87062d3
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/images/ui-bg_glass_65_ffffff_1x400.png
Binary files differ
diff --git a/htdocs/Libs/JQueryUI/images/ui-bg_glass_75_dadada_1x400.png b/htdocs/Libs/JQueryUI/images/ui-bg_glass_75_dadada_1x400.png
new file mode 100644
index 0000000..e7686e4
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/images/ui-bg_glass_75_dadada_1x400.png
Binary files differ
diff --git a/htdocs/Libs/JQueryUI/images/ui-bg_glass_75_e6e6e6_1x400.png b/htdocs/Libs/JQueryUI/images/ui-bg_glass_75_e6e6e6_1x400.png
new file mode 100644
index 0000000..dec05c4
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/images/ui-bg_glass_75_e6e6e6_1x400.png
Binary files differ
diff --git a/htdocs/Libs/JQueryUI/images/ui-bg_glass_95_fef1ec_1x400.png b/htdocs/Libs/JQueryUI/images/ui-bg_glass_95_fef1ec_1x400.png
new file mode 100644
index 0000000..3e3b02a
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/images/ui-bg_glass_95_fef1ec_1x400.png
Binary files differ
diff --git a/htdocs/Libs/JQueryUI/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/htdocs/Libs/JQueryUI/images/ui-bg_highlight-soft_75_cccccc_1x100.png
new file mode 100644
index 0000000..75b8952
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/images/ui-bg_highlight-soft_75_cccccc_1x100.png
Binary files differ
diff --git a/htdocs/Libs/JQueryUI/images/ui-icons_222222_256x240.png b/htdocs/Libs/JQueryUI/images/ui-icons_222222_256x240.png
new file mode 100644
index 0000000..e9c8e16
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/images/ui-icons_222222_256x240.png
Binary files differ
diff --git a/htdocs/Libs/JQueryUI/images/ui-icons_2e83ff_256x240.png b/htdocs/Libs/JQueryUI/images/ui-icons_2e83ff_256x240.png
new file mode 100644
index 0000000..f2bf838
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/images/ui-icons_2e83ff_256x240.png
Binary files differ
diff --git a/htdocs/Libs/JQueryUI/images/ui-icons_454545_256x240.png b/htdocs/Libs/JQueryUI/images/ui-icons_454545_256x240.png
new file mode 100644
index 0000000..d6169e8
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/images/ui-icons_454545_256x240.png
Binary files differ
diff --git a/htdocs/Libs/JQueryUI/images/ui-icons_888888_256x240.png b/htdocs/Libs/JQueryUI/images/ui-icons_888888_256x240.png
new file mode 100644
index 0000000..d3e6e02
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/images/ui-icons_888888_256x240.png
Binary files differ
diff --git a/htdocs/Libs/JQueryUI/images/ui-icons_cd0a0a_256x240.png b/htdocs/Libs/JQueryUI/images/ui-icons_cd0a0a_256x240.png
new file mode 100644
index 0000000..4937018
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/images/ui-icons_cd0a0a_256x240.png
Binary files differ
diff --git a/htdocs/Libs/JQueryUI/index.html b/htdocs/Libs/JQueryUI/index.html
new file mode 100644
index 0000000..b878272
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/index.html
@@ -0,0 +1,513 @@
+<!doctype html>
+<html lang="us">
+<head>
+	<meta charset="utf-8">
+	<title>jQuery UI Example Page</title>
+	<link href="jquery-ui.css" rel="stylesheet">
+	<style>
+	body{
+		font: 62.5% "Trebuchet MS", sans-serif;
+		margin: 50px;
+	}
+	.demoHeaders {
+		margin-top: 2em;
+	}
+	#dialog-link {
+		padding: .4em 1em .4em 20px;
+		text-decoration: none;
+		position: relative;
+	}
+	#dialog-link span.ui-icon {
+		margin: 0 5px 0 0;
+		position: absolute;
+		left: .2em;
+		top: 50%;
+		margin-top: -8px;
+	}
+	#icons {
+		margin: 0;
+		padding: 0;
+	}
+	#icons li {
+		margin: 2px;
+		position: relative;
+		padding: 4px 0;
+		cursor: pointer;
+		float: left;
+		list-style: none;
+	}
+	#icons span.ui-icon {
+		float: left;
+		margin: 0 4px;
+	}
+	.fakewindowcontain .ui-widget-overlay {
+		position: absolute;
+	}
+	select {
+		width: 200px;
+	}
+	</style>
+</head>
+<body>
+
+<h1>Welcome to jQuery UI!</h1>
+
+<div class="ui-widget">
+	<p>This page demonstrates the widgets and theme you selected in Download Builder. Please make sure you are using them with a compatible jQuery version.</p>
+</div>
+
+<h1>YOUR COMPONENTS:</h1>
+
+
+<!-- Accordion -->
+<h2 class="demoHeaders">Accordion</h2>
+<div id="accordion">
+	<h3>First</h3>
+	<div>Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet.</div>
+	<h3>Second</h3>
+	<div>Phasellus mattis tincidunt nibh.</div>
+	<h3>Third</h3>
+	<div>Nam dui erat, auctor a, dignissim quis.</div>
+</div>
+
+
+
+<!-- Autocomplete -->
+<h2 class="demoHeaders">Autocomplete</h2>
+<div>
+	<input id="autocomplete" title="type &quot;a&quot;">
+</div>
+
+
+
+<!-- Button -->
+<h2 class="demoHeaders">Button</h2>
+<button id="button">A button element</button>
+<form style="margin-top: 1em;">
+	<div id="radioset">
+		<input type="radio" id="radio1" name="radio"><label for="radio1">Choice 1</label>
+		<input type="radio" id="radio2" name="radio" checked="checked"><label for="radio2">Choice 2</label>
+		<input type="radio" id="radio3" name="radio"><label for="radio3">Choice 3</label>
+	</div>
+</form>
+
+
+
+<!-- Tabs -->
+<h2 class="demoHeaders">Tabs</h2>
+<div id="tabs">
+	<ul>
+		<li><a href="#tabs-1">First</a></li>
+		<li><a href="#tabs-2">Second</a></li>
+		<li><a href="#tabs-3">Third</a></li>
+	</ul>
+	<div id="tabs-1">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>
+	<div id="tabs-2">Phasellus mattis tincidunt nibh. Cras orci urna, blandit id, pretium vel, aliquet ornare, felis. Maecenas scelerisque sem non nisl. Fusce sed lorem in enim dictum bibendum.</div>
+	<div id="tabs-3">Nam dui erat, auctor a, dignissim quis, sollicitudin eu, felis. Pellentesque nisi urna, interdum eget, sagittis et, consequat vestibulum, lacus. Mauris porttitor ullamcorper augue.</div>
+</div>
+
+
+
+<!-- Dialog NOTE: Dialog is not generated by UI in this demo so it can be visually styled in themeroller-->
+<h2 class="demoHeaders">Dialog</h2>
+<p><a href="#" id="dialog-link" class="ui-state-default ui-corner-all"><span class="ui-icon ui-icon-newwin"></span>Open Dialog</a></p>
+
+<h2 class="demoHeaders">Overlay and Shadow Classes <em>(not currently used in UI widgets)</em></h2>
+<div style="position: relative; width: 96%; height: 200px; padding:1% 2%; overflow:hidden;" class="fakewindowcontain">
+	<p>Lorem ipsum dolor sit amet,  Nulla nec tortor. Donec id elit quis purus consectetur consequat. </p><p>Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id, sem. Morbi in orci. </p><p>Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur consequat. </p><p>Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. </p><p>Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. </p><p>Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. </p>
+
+	<!-- ui-dialog -->
+	<div class="ui-overlay"><div class="ui-widget-overlay"></div><div class="ui-widget-shadow ui-corner-all" style="width: 302px; height: 152px; position: absolute; left: 50px; top: 30px;"></div></div>
+	<div style="position: absolute; width: 280px; height: 130px;left: 50px; top: 30px; padding: 10px;" class="ui-widget ui-widget-content ui-corner-all">
+		<div class="ui-dialog-content ui-widget-content" style="background: none; border: 0;">
+			<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
+		</div>
+	</div>
+
+</div>
+
+<!-- ui-dialog -->
+<div id="dialog" title="Dialog Title">
+	<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
+</div>
+
+
+
+<h2 class="demoHeaders">Framework Icons (content color preview)</h2>
+<ul id="icons" class="ui-widget ui-helper-clearfix">
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-n"><span class="ui-icon ui-icon-carat-1-n"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-ne"><span class="ui-icon ui-icon-carat-1-ne"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-e"><span class="ui-icon ui-icon-carat-1-e"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-se"><span class="ui-icon ui-icon-carat-1-se"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-s"><span class="ui-icon ui-icon-carat-1-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-sw"><span class="ui-icon ui-icon-carat-1-sw"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-w"><span class="ui-icon ui-icon-carat-1-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-nw"><span class="ui-icon ui-icon-carat-1-nw"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-2-n-s"><span class="ui-icon ui-icon-carat-2-n-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-2-e-w"><span class="ui-icon ui-icon-carat-2-e-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-n"><span class="ui-icon ui-icon-triangle-1-n"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-ne"><span class="ui-icon ui-icon-triangle-1-ne"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-e"><span class="ui-icon ui-icon-triangle-1-e"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-se"><span class="ui-icon ui-icon-triangle-1-se"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-s"><span class="ui-icon ui-icon-triangle-1-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-sw"><span class="ui-icon ui-icon-triangle-1-sw"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-w"><span class="ui-icon ui-icon-triangle-1-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-nw"><span class="ui-icon ui-icon-triangle-1-nw"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-2-n-s"><span class="ui-icon ui-icon-triangle-2-n-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-2-e-w"><span class="ui-icon ui-icon-triangle-2-e-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-n"><span class="ui-icon ui-icon-arrow-1-n"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-ne"><span class="ui-icon ui-icon-arrow-1-ne"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-e"><span class="ui-icon ui-icon-arrow-1-e"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-se"><span class="ui-icon ui-icon-arrow-1-se"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-s"><span class="ui-icon ui-icon-arrow-1-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-sw"><span class="ui-icon ui-icon-arrow-1-sw"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-w"><span class="ui-icon ui-icon-arrow-1-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-nw"><span class="ui-icon ui-icon-arrow-1-nw"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-2-n-s"><span class="ui-icon ui-icon-arrow-2-n-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-2-ne-sw"><span class="ui-icon ui-icon-arrow-2-ne-sw"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-2-e-w"><span class="ui-icon ui-icon-arrow-2-e-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-2-se-nw"><span class="ui-icon ui-icon-arrow-2-se-nw"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowstop-1-n"><span class="ui-icon ui-icon-arrowstop-1-n"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowstop-1-e"><span class="ui-icon ui-icon-arrowstop-1-e"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowstop-1-s"><span class="ui-icon ui-icon-arrowstop-1-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowstop-1-w"><span class="ui-icon ui-icon-arrowstop-1-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-n"><span class="ui-icon ui-icon-arrowthick-1-n"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-ne"><span class="ui-icon ui-icon-arrowthick-1-ne"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-e"><span class="ui-icon ui-icon-arrowthick-1-e"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-se"><span class="ui-icon ui-icon-arrowthick-1-se"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-s"><span class="ui-icon ui-icon-arrowthick-1-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-sw"><span class="ui-icon ui-icon-arrowthick-1-sw"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-w"><span class="ui-icon ui-icon-arrowthick-1-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-nw"><span class="ui-icon ui-icon-arrowthick-1-nw"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-2-n-s"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-2-ne-sw"><span class="ui-icon ui-icon-arrowthick-2-ne-sw"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-2-e-w"><span class="ui-icon ui-icon-arrowthick-2-e-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-2-se-nw"><span class="ui-icon ui-icon-arrowthick-2-se-nw"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthickstop-1-n"><span class="ui-icon ui-icon-arrowthickstop-1-n"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthickstop-1-e"><span class="ui-icon ui-icon-arrowthickstop-1-e"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthickstop-1-s"><span class="ui-icon ui-icon-arrowthickstop-1-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthickstop-1-w"><span class="ui-icon ui-icon-arrowthickstop-1-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturnthick-1-w"><span class="ui-icon ui-icon-arrowreturnthick-1-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturnthick-1-n"><span class="ui-icon ui-icon-arrowreturnthick-1-n"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturnthick-1-e"><span class="ui-icon ui-icon-arrowreturnthick-1-e"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturnthick-1-s"><span class="ui-icon ui-icon-arrowreturnthick-1-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturn-1-w"><span class="ui-icon ui-icon-arrowreturn-1-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturn-1-n"><span class="ui-icon ui-icon-arrowreturn-1-n"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturn-1-e"><span class="ui-icon ui-icon-arrowreturn-1-e"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturn-1-s"><span class="ui-icon ui-icon-arrowreturn-1-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowrefresh-1-w"><span class="ui-icon ui-icon-arrowrefresh-1-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowrefresh-1-n"><span class="ui-icon ui-icon-arrowrefresh-1-n"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowrefresh-1-e"><span class="ui-icon ui-icon-arrowrefresh-1-e"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowrefresh-1-s"><span class="ui-icon ui-icon-arrowrefresh-1-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-4"><span class="ui-icon ui-icon-arrow-4"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-4-diag"><span class="ui-icon ui-icon-arrow-4-diag"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-extlink"><span class="ui-icon ui-icon-extlink"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-newwin"><span class="ui-icon ui-icon-newwin"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-refresh"><span class="ui-icon ui-icon-refresh"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-shuffle"><span class="ui-icon ui-icon-shuffle"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-transfer-e-w"><span class="ui-icon ui-icon-transfer-e-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-transferthick-e-w"><span class="ui-icon ui-icon-transferthick-e-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-folder-collapsed"><span class="ui-icon ui-icon-folder-collapsed"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-folder-open"><span class="ui-icon ui-icon-folder-open"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-document"><span class="ui-icon ui-icon-document"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-document-b"><span class="ui-icon ui-icon-document-b"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-note"><span class="ui-icon ui-icon-note"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-mail-closed"><span class="ui-icon ui-icon-mail-closed"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-mail-open"><span class="ui-icon ui-icon-mail-open"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-suitcase"><span class="ui-icon ui-icon-suitcase"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-comment"><span class="ui-icon ui-icon-comment"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-person"><span class="ui-icon ui-icon-person"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-print"><span class="ui-icon ui-icon-print"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-trash"><span class="ui-icon ui-icon-trash"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-locked"><span class="ui-icon ui-icon-locked"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-unlocked"><span class="ui-icon ui-icon-unlocked"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-bookmark"><span class="ui-icon ui-icon-bookmark"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-tag"><span class="ui-icon ui-icon-tag"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-home"><span class="ui-icon ui-icon-home"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-flag"><span class="ui-icon ui-icon-flag"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-calculator"><span class="ui-icon ui-icon-calculator"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-cart"><span class="ui-icon ui-icon-cart"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-pencil"><span class="ui-icon ui-icon-pencil"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-clock"><span class="ui-icon ui-icon-clock"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-disk"><span class="ui-icon ui-icon-disk"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-calendar"><span class="ui-icon ui-icon-calendar"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-zoomin"><span class="ui-icon ui-icon-zoomin"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-zoomout"><span class="ui-icon ui-icon-zoomout"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-search"><span class="ui-icon ui-icon-search"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-wrench"><span class="ui-icon ui-icon-wrench"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-gear"><span class="ui-icon ui-icon-gear"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-heart"><span class="ui-icon ui-icon-heart"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-star"><span class="ui-icon ui-icon-star"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-link"><span class="ui-icon ui-icon-link"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-cancel"><span class="ui-icon ui-icon-cancel"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-plus"><span class="ui-icon ui-icon-plus"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-plusthick"><span class="ui-icon ui-icon-plusthick"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-minus"><span class="ui-icon ui-icon-minus"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-minusthick"><span class="ui-icon ui-icon-minusthick"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-close"><span class="ui-icon ui-icon-close"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-closethick"><span class="ui-icon ui-icon-closethick"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-key"><span class="ui-icon ui-icon-key"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-lightbulb"><span class="ui-icon ui-icon-lightbulb"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-scissors"><span class="ui-icon ui-icon-scissors"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-clipboard"><span class="ui-icon ui-icon-clipboard"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-copy"><span class="ui-icon ui-icon-copy"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-contact"><span class="ui-icon ui-icon-contact"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-image"><span class="ui-icon ui-icon-image"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-video"><span class="ui-icon ui-icon-video"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-script"><span class="ui-icon ui-icon-script"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-alert"><span class="ui-icon ui-icon-alert"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-info"><span class="ui-icon ui-icon-info"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-notice"><span class="ui-icon ui-icon-notice"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-help"><span class="ui-icon ui-icon-help"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-check"><span class="ui-icon ui-icon-check"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-bullet"><span class="ui-icon ui-icon-bullet"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-radio-off"><span class="ui-icon ui-icon-radio-off"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-radio-on"><span class="ui-icon ui-icon-radio-on"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-pin-w"><span class="ui-icon ui-icon-pin-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-pin-s"><span class="ui-icon ui-icon-pin-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-play"><span class="ui-icon ui-icon-play"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-pause"><span class="ui-icon ui-icon-pause"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-seek-next"><span class="ui-icon ui-icon-seek-next"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-seek-prev"><span class="ui-icon ui-icon-seek-prev"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-seek-end"><span class="ui-icon ui-icon-seek-end"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-seek-first"><span class="ui-icon ui-icon-seek-first"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-stop"><span class="ui-icon ui-icon-stop"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-eject"><span class="ui-icon ui-icon-eject"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-volume-off"><span class="ui-icon ui-icon-volume-off"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-volume-on"><span class="ui-icon ui-icon-volume-on"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-power"><span class="ui-icon ui-icon-power"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-signal-diag"><span class="ui-icon ui-icon-signal-diag"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-signal"><span class="ui-icon ui-icon-signal"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-battery-0"><span class="ui-icon ui-icon-battery-0"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-battery-1"><span class="ui-icon ui-icon-battery-1"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-battery-2"><span class="ui-icon ui-icon-battery-2"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-battery-3"><span class="ui-icon ui-icon-battery-3"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-plus"><span class="ui-icon ui-icon-circle-plus"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-minus"><span class="ui-icon ui-icon-circle-minus"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-close"><span class="ui-icon ui-icon-circle-close"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-triangle-e"><span class="ui-icon ui-icon-circle-triangle-e"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-triangle-s"><span class="ui-icon ui-icon-circle-triangle-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-triangle-w"><span class="ui-icon ui-icon-circle-triangle-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-triangle-n"><span class="ui-icon ui-icon-circle-triangle-n"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-arrow-e"><span class="ui-icon ui-icon-circle-arrow-e"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-arrow-s"><span class="ui-icon ui-icon-circle-arrow-s"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-arrow-w"><span class="ui-icon ui-icon-circle-arrow-w"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-arrow-n"><span class="ui-icon ui-icon-circle-arrow-n"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-zoomin"><span class="ui-icon ui-icon-circle-zoomin"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-zoomout"><span class="ui-icon ui-icon-circle-zoomout"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-check"><span class="ui-icon ui-icon-circle-check"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circlesmall-plus"><span class="ui-icon ui-icon-circlesmall-plus"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circlesmall-minus"><span class="ui-icon ui-icon-circlesmall-minus"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-circlesmall-close"><span class="ui-icon ui-icon-circlesmall-close"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-squaresmall-plus"><span class="ui-icon ui-icon-squaresmall-plus"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-squaresmall-minus"><span class="ui-icon ui-icon-squaresmall-minus"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-squaresmall-close"><span class="ui-icon ui-icon-squaresmall-close"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-grip-dotted-vertical"><span class="ui-icon ui-icon-grip-dotted-vertical"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-grip-dotted-horizontal"><span class="ui-icon ui-icon-grip-dotted-horizontal"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-grip-solid-vertical"><span class="ui-icon ui-icon-grip-solid-vertical"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-grip-solid-horizontal"><span class="ui-icon ui-icon-grip-solid-horizontal"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-gripsmall-diagonal-se"><span class="ui-icon ui-icon-gripsmall-diagonal-se"></span></li>
+	<li class="ui-state-default ui-corner-all" title=".ui-icon-grip-diagonal-se"><span class="ui-icon ui-icon-grip-diagonal-se"></span></li>
+</ul>
+
+
+<!-- Slider -->
+<h2 class="demoHeaders">Slider</h2>
+<div id="slider"></div>
+
+
+
+<!-- Datepicker -->
+<h2 class="demoHeaders">Datepicker</h2>
+<div id="datepicker"></div>
+
+
+
+<!-- Progressbar -->
+<h2 class="demoHeaders">Progressbar</h2>
+<div id="progressbar"></div>
+
+
+
+<!-- Progressbar -->
+<h2 class="demoHeaders">Selectmenu</h2>
+<select id="selectmenu">
+	<option>Slower</option>
+	<option>Slow</option>
+	<option selected="selected">Medium</option>
+	<option>Fast</option>
+	<option>Faster</option>
+</select>
+
+
+
+<!-- Spinner -->
+<h2 class="demoHeaders">Spinner</h2>
+<input id="spinner">
+
+
+
+<!-- Menu -->
+<h2 class="demoHeaders">Menu</h2>
+<ul style="width:100px;" id="menu">
+	<li>Item 1</li>
+	<li>Item 2</li>
+	<li>Item 3
+		<ul>
+			<li>Item 3-1</li>
+			<li>Item 3-2</li>
+			<li>Item 3-3</li>
+			<li>Item 3-4</li>
+			<li>Item 3-5</li>
+		</ul>
+	</li>
+	<li>Item 4</li>
+	<li>Item 5</li>
+</ul>
+
+
+
+<!-- Tooltip -->
+<h2 class="demoHeaders">Tooltip</h2>
+<p id="tooltip">
+	<a href="#" title="That&apos;s what this widget is">Tooltips</a> can be attached to any element. When you hover
+the element with your mouse, the title attribute is displayed in a little box next to the element, just like a native tooltip.
+</p>
+
+
+<!-- Highlight / Error -->
+<h2 class="demoHeaders">Highlight / Error</h2>
+<div class="ui-widget">
+	<div class="ui-state-highlight ui-corner-all" style="margin-top: 20px; padding: 0 .7em;">
+		<p><span class="ui-icon ui-icon-info" style="float: left; margin-right: .3em;"></span>
+		<strong>Hey!</strong> Sample ui-state-highlight style.</p>
+	</div>
+</div>
+<br>
+<div class="ui-widget">
+	<div class="ui-state-error ui-corner-all" style="padding: 0 .7em;">
+		<p><span class="ui-icon ui-icon-alert" style="float: left; margin-right: .3em;"></span>
+		<strong>Alert:</strong> Sample ui-state-error style.</p>
+	</div>
+</div>
+
+<script src="external/jquery/jquery.js"></script>
+<script src="jquery-ui.js"></script>
+<script>
+
+$( "#accordion" ).accordion();
+
+
+
+var availableTags = [
+	"ActionScript",
+	"AppleScript",
+	"Asp",
+	"BASIC",
+	"C",
+	"C++",
+	"Clojure",
+	"COBOL",
+	"ColdFusion",
+	"Erlang",
+	"Fortran",
+	"Groovy",
+	"Haskell",
+	"Java",
+	"JavaScript",
+	"Lisp",
+	"Perl",
+	"PHP",
+	"Python",
+	"Ruby",
+	"Scala",
+	"Scheme"
+];
+$( "#autocomplete" ).autocomplete({
+	source: availableTags
+});
+
+
+
+$( "#button" ).button();
+$( "#radioset" ).buttonset();
+
+
+
+$( "#tabs" ).tabs();
+
+
+
+$( "#dialog" ).dialog({
+	autoOpen: false,
+	width: 400,
+	buttons: [
+		{
+			text: "Ok",
+			click: function() {
+				$( this ).dialog( "close" );
+			}
+		},
+		{
+			text: "Cancel",
+			click: function() {
+				$( this ).dialog( "close" );
+			}
+		}
+	]
+});
+
+// Link to open the dialog
+$( "#dialog-link" ).click(function( event ) {
+	$( "#dialog" ).dialog( "open" );
+	event.preventDefault();
+});
+
+
+
+$( "#datepicker" ).datepicker({
+	inline: true
+});
+
+
+
+$( "#slider" ).slider({
+	range: true,
+	values: [ 17, 67 ]
+});
+
+
+
+$( "#progressbar" ).progressbar({
+	value: 20
+});
+
+
+
+$( "#spinner" ).spinner();
+
+
+
+$( "#menu" ).menu();
+
+
+
+$( "#tooltip" ).tooltip();
+
+
+
+$( "#selectmenu" ).selectmenu();
+
+
+// Hover states on the static widgets
+$( "#dialog-link, #icons li" ).hover(
+	function() {
+		$( this ).addClass( "ui-state-hover" );
+	},
+	function() {
+		$( this ).removeClass( "ui-state-hover" );
+	}
+);
+</script>
+</body>
+</html>
diff --git a/htdocs/Libs/JQueryUI/jquery-ui.css b/htdocs/Libs/JQueryUI/jquery-ui.css
new file mode 100644
index 0000000..5038b48
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/jquery-ui.css
@@ -0,0 +1,1263 @@
+/*! jQuery UI - v1.11.4 - 2016-04-11
+* http://jqueryui.com
+* Includes: core.css, draggable.css, resizable.css, selectable.css, sortable.css, accordion.css, autocomplete.css, button.css, datepicker.css, dialog.css, menu.css, progressbar.css, selectmenu.css, slider.css, spinner.css, tabs.css, tooltip.css, theme.css
+* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden {
+	display: none;
+}
+.ui-helper-hidden-accessible {
+	border: 0;
+	clip: rect(0 0 0 0);
+	height: 1px;
+	margin: -1px;
+	overflow: hidden;
+	padding: 0;
+	position: absolute;
+	width: 1px;
+}
+.ui-helper-reset {
+	margin: 0;
+	padding: 0;
+	border: 0;
+	outline: 0;
+	/*line-height: 1.3;*/
+	text-decoration: none;
+	font-size: 100%;
+	list-style: none;
+}
+.ui-helper-clearfix:before,
+.ui-helper-clearfix:after {
+	content: "";
+	display: table;
+	border-collapse: collapse;
+}
+.ui-helper-clearfix:after {
+	clear: both;
+}
+.ui-helper-clearfix {
+	min-height: 0; /* support: IE7 */
+}
+.ui-helper-zfix {
+	width: 100%;
+	height: 100%;
+	top: 0;
+	left: 0;
+	position: absolute;
+	opacity: 0;
+	filter:Alpha(Opacity=0); /* support: IE8 */
+}
+
+.ui-front {
+	z-index: 100;
+}
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled {
+	cursor: default !important;
+}
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+	display: block;
+	text-indent: -99999px;
+	overflow: hidden;
+	background-repeat: no-repeat;
+}
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay {
+	position: fixed;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+}
+.ui-draggable-handle {
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-resizable {
+	position: relative;
+}
+.ui-resizable-handle {
+	position: absolute;
+	font-size: 0.1px;
+	display: block;
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-resizable-disabled .ui-resizable-handle,
+.ui-resizable-autohide .ui-resizable-handle {
+	display: none;
+}
+.ui-resizable-n {
+	cursor: n-resize;
+	height: 7px;
+	width: 100%;
+	top: -5px;
+	left: 0;
+}
+.ui-resizable-s {
+	cursor: s-resize;
+	height: 7px;
+	width: 100%;
+	bottom: -5px;
+	left: 0;
+}
+.ui-resizable-e {
+	cursor: e-resize;
+	width: 7px;
+	right: -5px;
+	top: 0;
+	height: 100%;
+}
+.ui-resizable-w {
+	cursor: w-resize;
+	width: 7px;
+	left: -5px;
+	top: 0;
+	height: 100%;
+}
+.ui-resizable-se {
+	cursor: se-resize;
+	width: 12px;
+	height: 12px;
+	right: 1px;
+	bottom: 1px;
+}
+.ui-resizable-sw {
+	cursor: sw-resize;
+	width: 9px;
+	height: 9px;
+	left: -5px;
+	bottom: -5px;
+}
+.ui-resizable-nw {
+	cursor: nw-resize;
+	width: 9px;
+	height: 9px;
+	left: -5px;
+	top: -5px;
+}
+.ui-resizable-ne {
+	cursor: ne-resize;
+	width: 9px;
+	height: 9px;
+	right: -5px;
+	top: -5px;
+}
+.ui-selectable {
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-selectable-helper {
+	position: absolute;
+	z-index: 100;
+	border: 1px dotted black;
+}
+.ui-sortable-handle {
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-accordion .ui-accordion-header {
+	display: block;
+	cursor: pointer;
+	position: relative;
+	margin: 2px 0 0 0;
+	padding: .5em .5em .5em .7em;
+	min-height: 0; /* support: IE7 */
+	font-size: 100%;
+}
+.ui-accordion .ui-accordion-icons {
+	padding-left: 2.2em;
+}
+.ui-accordion .ui-accordion-icons .ui-accordion-icons {
+	padding-left: 2.2em;
+}
+.ui-accordion .ui-accordion-header .ui-accordion-header-icon {
+	position: absolute;
+	left: .5em;
+	top: 50%;
+	margin-top: -8px;
+}
+.ui-accordion .ui-accordion-content {
+	padding: 1em 2.2em;
+	border-top: 0;
+	overflow: auto;
+}
+.ui-autocomplete {
+	position: absolute;
+	top: 0;
+	left: 0;
+	cursor: default;
+}
+.ui-button {
+	display: inline-block;
+	position: relative;
+	padding: 0;
+	/*line-height: normal;*/
+	margin-right: .1em;
+	cursor: pointer;
+	vertical-align: middle;
+	text-align: center;
+	overflow: visible; /* removes extra width in IE */
+}
+.ui-button,
+.ui-button:link,
+.ui-button:visited,
+.ui-button:hover,
+.ui-button:active {
+	/*text-decoration: none;*/
+}
+/* to make room for the icon, a width needs to be set here */
+.ui-button-icon-only {
+	width: 2.2em;
+}
+/* button elements seem to need a little more width */
+button.ui-button-icon-only {
+	width: 2.4em;
+}
+.ui-button-icons-only {
+	width: 3.4em;
+}
+button.ui-button-icons-only {
+	width: 3.7em;
+}
+
+/* button text element */
+.ui-button .ui-button-text {
+	display: block;
+	/*line-height: normal;*/
+}
+.ui-button-text-only .ui-button-text {
+	padding: .4em 1em;
+}
+.ui-button-icon-only .ui-button-text,
+.ui-button-icons-only .ui-button-text {
+	padding: .4em;
+	text-indent: -9999999px;
+}
+.ui-button-text-icon-primary .ui-button-text,
+.ui-button-text-icons .ui-button-text {
+	padding: .4em 1em .4em 2.1em;
+}
+.ui-button-text-icon-secondary .ui-button-text,
+.ui-button-text-icons .ui-button-text {
+	padding: .4em 2.1em .4em 1em;
+}
+.ui-button-text-icons .ui-button-text {
+	padding-left: 2.1em;
+	padding-right: 2.1em;
+}
+/* no icon support for input elements, provide padding by default */
+input.ui-button {
+	padding: .4em 1em;
+}
+
+/* button icon element(s) */
+.ui-button-icon-only .ui-icon,
+.ui-button-text-icon-primary .ui-icon,
+.ui-button-text-icon-secondary .ui-icon,
+.ui-button-text-icons .ui-icon,
+.ui-button-icons-only .ui-icon {
+	position: absolute;
+	top: 50%;
+	margin-top: -8px;
+}
+.ui-button-icon-only .ui-icon {
+	left: 50%;
+	margin-left: -8px;
+}
+.ui-button-text-icon-primary .ui-button-icon-primary,
+.ui-button-text-icons .ui-button-icon-primary,
+.ui-button-icons-only .ui-button-icon-primary {
+	left: .5em;
+}
+.ui-button-text-icon-secondary .ui-button-icon-secondary,
+.ui-button-text-icons .ui-button-icon-secondary,
+.ui-button-icons-only .ui-button-icon-secondary {
+	right: .5em;
+}
+
+/* button sets */
+.ui-buttonset {
+	margin-right: 7px;
+}
+.ui-buttonset .ui-button {
+	margin-left: 0;
+	margin-right: -.3em;
+}
+
+/* workarounds */
+/* reset extra padding in Firefox, see h5bp.com/l */
+input.ui-button::-moz-focus-inner,
+button.ui-button::-moz-focus-inner {
+	border: 0;
+	padding: 0;
+	outline:none;
+}
+.ui-datepicker {
+	width: 17em;
+	padding: .2em .2em 0;
+	display: none;
+}
+.ui-datepicker .ui-datepicker-header {
+	position: relative;
+	padding: .2em 0;
+}
+.ui-datepicker .ui-datepicker-prev,
+.ui-datepicker .ui-datepicker-next {
+	position: absolute;
+	top: 2px;
+	width: 1.8em;
+	height: 1.8em;
+}
+.ui-datepicker .ui-datepicker-prev-hover,
+.ui-datepicker .ui-datepicker-next-hover {
+	top: 1px;
+}
+.ui-datepicker .ui-datepicker-prev {
+	left: 2px;
+}
+.ui-datepicker .ui-datepicker-next {
+	right: 2px;
+}
+.ui-datepicker .ui-datepicker-prev-hover {
+	left: 1px;
+}
+.ui-datepicker .ui-datepicker-next-hover {
+	right: 1px;
+}
+.ui-datepicker .ui-datepicker-prev span,
+.ui-datepicker .ui-datepicker-next span {
+	display: block;
+	position: absolute;
+	left: 50%;
+	margin-left: -8px;
+	top: 50%;
+	margin-top: -8px;
+}
+.ui-datepicker .ui-datepicker-title {
+	margin: 0 2.3em;
+	/*line-height: 1.8em;*/
+	text-align: center;
+}
+.ui-datepicker .ui-datepicker-title select {
+	font-size: 1em;
+	margin: 1px 0;
+}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year {
+	width: 45%;
+}
+.ui-datepicker table {
+	width: 100%;
+	font-size: .9em;
+	border-collapse: collapse;
+	margin: 0 0 .4em;
+}
+.ui-datepicker th {
+	padding: .7em .3em;
+	text-align: center;
+	font-weight: bold;
+	border: 0;
+}
+.ui-datepicker td {
+	border: 0;
+	padding: 1px;
+}
+.ui-datepicker td span,
+.ui-datepicker td a {
+	display: block;
+	padding: .2em;
+	text-align: right;
+	text-decoration: none;
+}
+.ui-datepicker .ui-datepicker-buttonpane {
+	background-image: none;
+	margin: .7em 0 0 0;
+	padding: 0 .2em;
+	border-left: 0;
+	border-right: 0;
+	border-bottom: 0;
+}
+.ui-datepicker .ui-datepicker-buttonpane button {
+	float: right;
+	margin: .5em .2em .4em;
+	cursor: pointer;
+	padding: .2em .6em .3em .6em;
+	width: auto;
+	overflow: visible;
+}
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
+	float: left;
+}
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi {
+	width: auto;
+}
+.ui-datepicker-multi .ui-datepicker-group {
+	float: left;
+}
+.ui-datepicker-multi .ui-datepicker-group table {
+	width: 95%;
+	margin: 0 auto .4em;
+}
+.ui-datepicker-multi-2 .ui-datepicker-group {
+	width: 50%;
+}
+.ui-datepicker-multi-3 .ui-datepicker-group {
+	width: 33.3%;
+}
+.ui-datepicker-multi-4 .ui-datepicker-group {
+	width: 25%;
+}
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
+	border-left-width: 0;
+}
+.ui-datepicker-multi .ui-datepicker-buttonpane {
+	clear: left;
+}
+.ui-datepicker-row-break {
+	clear: both;
+	width: 100%;
+	font-size: 0;
+}
+
+/* RTL support */
+.ui-datepicker-rtl {
+	direction: rtl;
+}
+.ui-datepicker-rtl .ui-datepicker-prev {
+	right: 2px;
+	left: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-next {
+	left: 2px;
+	right: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-prev:hover {
+	right: 1px;
+	left: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-next:hover {
+	left: 1px;
+	right: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane {
+	clear: right;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane button {
+	float: left;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
+.ui-datepicker-rtl .ui-datepicker-group {
+	float: right;
+}
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
+	border-right-width: 0;
+	border-left-width: 1px;
+}
+.ui-dialog {
+	overflow: hidden;
+	position: absolute;
+	top: 0;
+	left: 0;
+	padding: .2em;
+	outline: 0;
+}
+.ui-dialog .ui-dialog-titlebar {
+	padding: .4em 1em;
+	position: relative;
+}
+.ui-dialog .ui-dialog-title {
+	float: left;
+	margin: .1em 0;
+	white-space: nowrap;
+	width: 90%;
+	overflow: hidden;
+	text-overflow: ellipsis;
+}
+.ui-dialog .ui-dialog-titlebar-close {
+	position: absolute;
+	right: .3em;
+	top: 50%;
+	width: 20px;
+	margin: -10px 0 0 0;
+	padding: 1px;
+	height: 20px;
+}
+.ui-dialog .ui-dialog-content {
+	position: relative;
+	border: 0;
+	padding: .5em 1em;
+	background: none;
+	overflow: auto;
+}
+.ui-dialog .ui-dialog-buttonpane {
+	text-align: left;
+	border-width: 1px 0 0 0;
+	background-image: none;
+	margin-top: .5em;
+	padding: .3em 1em .5em .4em;
+}
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
+	float: right;
+}
+.ui-dialog .ui-dialog-buttonpane button {
+	margin: .5em .4em .5em 0;
+	cursor: pointer;
+}
+.ui-dialog .ui-resizable-se {
+	width: 12px;
+	height: 12px;
+	right: -5px;
+	bottom: -5px;
+	background-position: 16px 16px;
+}
+.ui-draggable .ui-dialog-titlebar {
+	cursor: move;
+}
+.ui-menu {
+	list-style: none;
+	padding: 0;
+	margin: 0;
+	display: block;
+	outline: none;
+}
+.ui-menu .ui-menu {
+	position: absolute;
+}
+.ui-menu .ui-menu-item {
+	position: relative;
+	margin: 0;
+	padding: 3px 1em 3px .4em;
+	cursor: pointer;
+	min-height: 0; /* support: IE7 */
+	/* support: IE10, see #8844 */
+	list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
+}
+.ui-menu .ui-menu-divider {
+	margin: 5px 0;
+	height: 0;
+	font-size: 0;
+	/*line-height: 0;*/
+	border-width: 1px 0 0 0;
+}
+.ui-menu .ui-state-focus,
+.ui-menu .ui-state-active {
+	margin: -1px;
+	outline:none;
+}
+
+/* icon support */
+.ui-menu-icons {
+	position: relative;
+}
+.ui-menu-icons .ui-menu-item {
+	padding-left: 2em;
+}
+
+/* left-aligned */
+.ui-menu .ui-icon {
+	position: absolute;
+	top: 0;
+	bottom: 0;
+	left: .2em;
+	margin: auto 0;
+}
+
+/* right-aligned */
+.ui-menu .ui-menu-icon {
+	left: auto;
+	right: 0;
+}
+.ui-progressbar {
+	height: 2em;
+	text-align: left;
+	overflow: hidden;
+}
+.ui-progressbar .ui-progressbar-value {
+	margin: -1px;
+	height: 100%;
+}
+.ui-progressbar .ui-progressbar-overlay {
+	background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");
+	height: 100%;
+	filter: alpha(opacity=25); /* support: IE8 */
+	opacity: 0.25;
+}
+.ui-progressbar-indeterminate .ui-progressbar-value {
+	background-image: none;
+}
+.ui-selectmenu-menu {
+	padding: 0;
+	margin: 0;
+	position: absolute;
+	top: 0;
+	left: 0;
+	display: none;
+}
+.ui-selectmenu-menu .ui-menu {
+	overflow: auto;
+	/* Support: IE7 */
+	overflow-x: hidden;
+	padding-bottom: 1px;
+}
+.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup {
+	font-size: 1em;
+	font-weight: bold;
+	/*line-height: 1.5;*/
+	padding: 2px 0.4em;
+	margin: 0.5em 0 0 0;
+	height: auto;
+	border: 0;
+}
+.ui-selectmenu-open {
+	display: block;
+}
+.ui-selectmenu-button {
+	display: inline-block;
+	overflow: hidden;
+	position: relative;
+	text-decoration: none;
+	cursor: pointer;
+}
+.ui-selectmenu-button span.ui-icon {
+	right: 0.5em;
+	left: auto;
+	margin-top: -8px;
+	position: absolute;
+	top: 50%;
+}
+.ui-selectmenu-button span.ui-selectmenu-text {
+	text-align: left;
+	padding: 0.4em 2.1em 0.4em 1em;
+	display: block;
+	/*line-height: 1.4;*/
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+}
+.ui-slider {
+	position: relative;
+	text-align: left;
+}
+.ui-slider .ui-slider-handle {
+	position: absolute;
+	z-index: 2;
+	width: 1.2em;
+	height: 1.2em;
+	cursor: default;
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-slider .ui-slider-range {
+	position: absolute;
+	z-index: 1;
+	font-size: .7em;
+	display: block;
+	border: 0;
+	background-position: 0 0;
+}
+
+/* support: IE8 - See #6727 */
+.ui-slider.ui-state-disabled .ui-slider-handle,
+.ui-slider.ui-state-disabled .ui-slider-range {
+	filter: inherit;
+}
+
+.ui-slider-horizontal {
+	height: .8em;
+}
+.ui-slider-horizontal .ui-slider-handle {
+	top: -.3em;
+	margin-left: -.6em;
+}
+.ui-slider-horizontal .ui-slider-range {
+	top: 0;
+	height: 100%;
+}
+.ui-slider-horizontal .ui-slider-range-min {
+	left: 0;
+}
+.ui-slider-horizontal .ui-slider-range-max {
+	right: 0;
+}
+
+.ui-slider-vertical {
+	width: .8em;
+	height: 100px;
+}
+.ui-slider-vertical .ui-slider-handle {
+	left: -.3em;
+	margin-left: 0;
+	margin-bottom: -.6em;
+}
+.ui-slider-vertical .ui-slider-range {
+	left: 0;
+	width: 100%;
+}
+.ui-slider-vertical .ui-slider-range-min {
+	bottom: 0;
+}
+.ui-slider-vertical .ui-slider-range-max {
+	top: 0;
+}
+.ui-spinner {
+	position: relative;
+	display: inline-block;
+	overflow: hidden;
+	padding: 0;
+	vertical-align: middle;
+}
+.ui-spinner-input {
+	border: none;
+	background: none;
+	color: inherit;
+	padding: 0;
+	margin: .2em 0;
+	vertical-align: middle;
+	margin-left: .4em;
+	margin-right: 22px;
+}
+.ui-spinner-button {
+	width: 16px;
+	height: 50%;
+	font-size: .5em;
+	padding: 0;
+	margin: 0;
+	text-align: center;
+	position: absolute;
+	cursor: default;
+	display: block;
+	overflow: hidden;
+	right: 0;
+}
+/* more specificity required here to override default borders */
+.ui-spinner a.ui-spinner-button {
+	border-top: none;
+	border-bottom: none;
+	border-right: none;
+}
+/* vertically center icon */
+.ui-spinner .ui-icon {
+	position: absolute;
+	margin-top: -8px;
+	top: 50%;
+	left: 0;
+}
+.ui-spinner-up {
+	top: 0;
+}
+.ui-spinner-down {
+	bottom: 0;
+}
+
+/* TR overrides */
+.ui-spinner .ui-icon-triangle-1-s {
+	/* need to fix icons sprite */
+	background-position: -65px -16px;
+}
+/* div*/
+.ui-tabs {
+    display: block;
+    width: 100%;
+    background-color: #d5d5d5;
+    border-bottom: 2px solid #f1f1f1;
+    vertical-align:top;
+}
+/* ul */
+.ui-tabs .ui-tabs-nav {
+    list-style-type: none;
+    margin: 0;
+    padding: 0;
+    overflow: hidden;
+}
+/* li */
+.ui-tabs .ui-tabs-nav li {
+    float: left;
+    display: inline-block;
+    color: #000;
+    background-color: #c5c5c5;
+    text-align: center;
+    padding: 6px 0px;
+    text-decoration: none;
+}
+.ui-tabs-anchor:hover {
+    background-color: #999;
+    color: white !important;
+}
+/* a */
+.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
+	padding: 6px;
+    text-decoration: none;
+    cursor:pointer;
+}
+/* active */
+.ui-tabs .ui-tabs-nav li.ui-tabs-active {
+    background-color: #4CAF50;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
+    color: white;
+    background-color: #4CAF50 !important;
+}
+
+.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
+	/*cursor: text;*/
+}
+.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
+	/*cursor: pointer;*/
+}
+.ui-tabs .ui-tabs-panel {
+	display: block;
+	border-width: 0;
+	padding: 0.2em 0.2em;
+	background: none;
+}
+.ui-tooltip {
+	padding: 8px;
+	position: absolute;
+	z-index: 9999;
+	max-width: 300px;
+	-webkit-box-shadow: 0 0 5px #aaa;
+	box-shadow: 0 0 5px #aaa;
+}
+body .ui-tooltip {
+	border-width: 2px;
+}
+
+/* Component containers
+----------------------------------*/
+.ui-widget {
+	/*font-family: Verdana,Arial,sans-serif;*/
+	/*font-size: 1.1em;*/
+}
+.ui-widget .ui-widget {
+	/*font-size: 1em;*/
+}
+.ui-widget input,
+.ui-widget select,
+.ui-widget textarea,
+.ui-widget button {
+	/*
+    font-family: Verdana,Arial,sans-serif;
+	font-size: 1em;
+    */
+}
+.ui-widget-content {
+    /*border: 1px solid #aaaaaa;*/
+	background: #eeeeee;
+	/*background: #ffffff;
+	color: #222222;*/
+}
+.ui-widget-content a {
+	color: #222222;
+}
+.ui-widget-header {
+	border-bottom:1px solid #aaaaaa;
+	/*background: #cccccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x;
+	color: #222222;
+	font-weight: bold;*/
+}
+.ui-widget-header a {
+	color: #222222;
+}
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default,
+.ui-widget-content .ui-state-default,
+.ui-widget-header .ui-state-default {
+	/*
+    border: 1px solid #d3d3d3;
+	background: #e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x;
+	font-weight: normal;
+	color: #555555;
+    */
+}
+.ui-state-default a,
+.ui-state-default a:link,
+.ui-state-default a:visited {
+    /*
+    color: #555555;
+	text-decoration: none;
+    */
+}
+.ui-state-hover,
+.ui-widget-content .ui-state-hover,
+.ui-widget-header .ui-state-hover,
+.ui-state-focus,
+.ui-widget-content .ui-state-focus,
+.ui-widget-header .ui-state-focus {
+	/*
+    border: 1px solid #999999;
+	background: #dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x;
+	font-weight: normal;
+	color: #212121;
+	outline:none;
+    */
+}
+.ui-state-hover a,
+.ui-state-hover a:hover,
+.ui-state-hover a:link,
+.ui-state-hover a:visited,
+.ui-state-focus a,
+.ui-state-focus a:hover,
+.ui-state-focus a:link,
+.ui-state-focus a:visited {
+    /*
+    color: #212121;
+	text-decoration: none;
+	outline:none;
+    */
+}
+.ui-state-active,
+.ui-widget-content .ui-state-active,
+.ui-widget-header .ui-state-active {
+    /*
+    border: 1px solid #aaaaaa;
+	background: #bbbbbb;
+	font-weight: normal;
+	color: #212121;
+    */
+}
+.ui-state-active a,
+.ui-state-active a:link,
+.ui-state-active a:visited {
+    /*
+    color: #212121;
+	text-decoration: none;
+    */
+}
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight,
+.ui-widget-content .ui-state-highlight,
+.ui-widget-header .ui-state-highlight {
+	/*
+    border: 1px solid #fcefa1;
+	background: #fbf9ee;
+	color: #363636;
+    */
+}
+.ui-state-highlight a,
+.ui-widget-content .ui-state-highlight a,
+.ui-widget-header .ui-state-highlight a {
+	/*color: #363636;*/
+}
+.ui-state-error,
+.ui-widget-content .ui-state-error,
+.ui-widget-header .ui-state-error {
+	border: 1px solid #cd0a0a;
+	background: #fef1ec; /*url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;*/
+	color: #cd0a0a;
+}
+.ui-state-error a,
+.ui-widget-content .ui-state-error a,
+.ui-widget-header .ui-state-error a {
+	color: #cd0a0a;
+}
+.ui-state-error-text,
+.ui-widget-content .ui-state-error-text,
+.ui-widget-header .ui-state-error-text {
+	color: #cd0a0a;
+}
+.ui-priority-primary,
+.ui-widget-content .ui-priority-primary,
+.ui-widget-header .ui-priority-primary {
+	font-weight: bold;
+}
+.ui-priority-secondary,
+.ui-widget-content .ui-priority-secondary,
+.ui-widget-header .ui-priority-secondary {
+	opacity: .7;
+	filter:Alpha(Opacity=70); /* support: IE8 */
+	font-weight: normal;
+}
+.ui-state-disabled,
+.ui-widget-content .ui-state-disabled,
+.ui-widget-header .ui-state-disabled {
+	opacity: .35;
+	filter:Alpha(Opacity=35); /* support: IE8 */
+	background-image: none;
+}
+.ui-state-disabled .ui-icon {
+	filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
+}
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+	width: 16px;
+	height: 16px;
+}
+.ui-icon,
+.ui-widget-content .ui-icon {
+	background-image: url("images/ui-icons_222222_256x240.png");
+}
+.ui-widget-header .ui-icon {
+	background-image: url("images/ui-icons_222222_256x240.png");
+}
+.ui-state-default .ui-icon {
+	background-image: url("images/ui-icons_888888_256x240.png");
+}
+.ui-state-hover .ui-icon,
+.ui-state-focus .ui-icon {
+	background-image: url("images/ui-icons_454545_256x240.png");
+	outline:none;
+}
+.ui-state-active .ui-icon {
+	background-image: url("images/ui-icons_454545_256x240.png");
+}
+.ui-state-highlight .ui-icon {
+	background-image: url("images/ui-icons_2e83ff_256x240.png");
+}
+.ui-state-error .ui-icon,
+.ui-state-error-text .ui-icon {
+	background-image: url("images/ui-icons_cd0a0a_256x240.png");
+}
+
+/* positioning */
+.ui-icon-blank { background-position: 16px 16px; }
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-on { background-position: -96px -144px; }
+.ui-icon-radio-off { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-left,
+.ui-corner-tl {
+	/*border-top-left-radius: 4px;*/
+}
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-right,
+.ui-corner-tr {
+	/*border-top-right-radius: 4px;*/
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-left,
+.ui-corner-bl {
+	/*border-bottom-left-radius: 4px;*/
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-right,
+.ui-corner-br {
+	/*border-bottom-right-radius: 4px;*/
+}
+
+/* Overlays */
+.ui-widget-overlay {
+	background: #aaaaaa;
+	opacity: .3;
+}
+.ui-widget-shadow {
+	margin: -8px 0 0 -8px;
+	padding: 8px;
+	background: #aaaaaa;
+	opacity: .3;
+	filter: Alpha(Opacity=30); /* support: IE8 */
+	border-radius: 8px;
+}
diff --git a/htdocs/Libs/JQueryUI/jquery-ui.js b/htdocs/Libs/JQueryUI/jquery-ui.js
new file mode 100644
index 0000000..912dcc0
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/jquery-ui.js
@@ -0,0 +1,16617 @@
+/*! jQuery UI - v1.11.4 - 2016-04-10
+* http://jqueryui.com
+* Includes: core.js, widget.js, mouse.js, position.js, draggable.js, droppable.js, resizable.js, selectable.js, sortable.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, menu.js, progressbar.js, selectmenu.js, slider.js, spinner.js, tabs.js, tooltip.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+(function( factory ) {
+	if ( typeof define === "function" && define.amd ) {
+
+		// AMD. Register as an anonymous module.
+		define([ "jquery" ], factory );
+	} else {
+
+		// Browser globals
+		factory( jQuery );
+	}
+}(function( $ ) {
+/*!
+ * jQuery UI Core 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/ui-core/
+ */
+
+
+// $.ui might exist from components with no dependencies, e.g., $.ui.position
+$.ui = $.ui || {};
+
+$.extend( $.ui, {
+	version: "1.11.4",
+
+	keyCode: {
+		BACKSPACE: 8,
+		COMMA: 188,
+		DELETE: 46,
+		DOWN: 40,
+		END: 35,
+		ENTER: 13,
+		ESCAPE: 27,
+		HOME: 36,
+		LEFT: 37,
+		PAGE_DOWN: 34,
+		PAGE_UP: 33,
+		PERIOD: 190,
+		RIGHT: 39,
+		SPACE: 32,
+		TAB: 9,
+		UP: 38
+	}
+});
+
+// plugins
+$.fn.extend({
+	scrollParent: function( includeHidden ) {
+		var position = this.css( "position" ),
+			excludeStaticParent = position === "absolute",
+			overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
+			scrollParent = this.parents().filter( function() {
+				var parent = $( this );
+				if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
+					return false;
+				}
+				return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) );
+			}).eq( 0 );
+
+		return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent;
+	},
+
+	uniqueId: (function() {
+		var uuid = 0;
+
+		return function() {
+			return this.each(function() {
+				if ( !this.id ) {
+					this.id = "ui-id-" + ( ++uuid );
+				}
+			});
+		};
+	})(),
+
+	removeUniqueId: function() {
+		return this.each(function() {
+			if ( /^ui-id-\d+$/.test( this.id ) ) {
+				$( this ).removeAttr( "id" );
+			}
+		});
+	}
+});
+
+// selectors
+function focusable( element, isTabIndexNotNaN ) {
+	var map, mapName, img,
+		nodeName = element.nodeName.toLowerCase();
+	if ( "area" === nodeName ) {
+		map = element.parentNode;
+		mapName = map.name;
+		if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
+			return false;
+		}
+		img = $( "img[usemap='#" + mapName + "']" )[ 0 ];
+		return !!img && visible( img );
+	}
+	return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ?
+		!element.disabled :
+		"a" === nodeName ?
+			element.href || isTabIndexNotNaN :
+			isTabIndexNotNaN) &&
+		// the element and all of its ancestors must be visible
+		visible( element );
+}
+
+function visible( element ) {
+	return $.expr.filters.visible( element ) &&
+		!$( element ).parents().addBack().filter(function() {
+			return $.css( this, "visibility" ) === "hidden";
+		}).length;
+}
+
+$.extend( $.expr[ ":" ], {
+	data: $.expr.createPseudo ?
+		$.expr.createPseudo(function( dataName ) {
+			return function( elem ) {
+				return !!$.data( elem, dataName );
+			};
+		}) :
+		// support: jQuery <1.8
+		function( elem, i, match ) {
+			return !!$.data( elem, match[ 3 ] );
+		},
+
+	focusable: function( element ) {
+		return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
+	},
+
+	tabbable: function( element ) {
+		var tabIndex = $.attr( element, "tabindex" ),
+			isTabIndexNaN = isNaN( tabIndex );
+		return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
+	}
+});
+
+// support: jQuery <1.8
+if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
+	$.each( [ "Width", "Height" ], function( i, name ) {
+		var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
+			type = name.toLowerCase(),
+			orig = {
+				innerWidth: $.fn.innerWidth,
+				innerHeight: $.fn.innerHeight,
+				outerWidth: $.fn.outerWidth,
+				outerHeight: $.fn.outerHeight
+			};
+
+		function reduce( elem, size, border, margin ) {
+			$.each( side, function() {
+				size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
+				if ( border ) {
+					size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
+				}
+				if ( margin ) {
+					size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
+				}
+			});
+			return size;
+		}
+
+		$.fn[ "inner" + name ] = function( size ) {
+			if ( size === undefined ) {
+				return orig[ "inner" + name ].call( this );
+			}
+
+			return this.each(function() {
+				$( this ).css( type, reduce( this, size ) + "px" );
+			});
+		};
+
+		$.fn[ "outer" + name] = function( size, margin ) {
+			if ( typeof size !== "number" ) {
+				return orig[ "outer" + name ].call( this, size );
+			}
+
+			return this.each(function() {
+				$( this).css( type, reduce( this, size, true, margin ) + "px" );
+			});
+		};
+	});
+}
+
+// support: jQuery <1.8
+if ( !$.fn.addBack ) {
+	$.fn.addBack = function( selector ) {
+		return this.add( selector == null ?
+			this.prevObject : this.prevObject.filter( selector )
+		);
+	};
+}
+
+// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
+if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
+	$.fn.removeData = (function( removeData ) {
+		return function( key ) {
+			if ( arguments.length ) {
+				return removeData.call( this, $.camelCase( key ) );
+			} else {
+				return removeData.call( this );
+			}
+		};
+	})( $.fn.removeData );
+}
+
+// deprecated
+$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
+
+$.fn.extend({
+	focus: (function( orig ) {
+		return function( delay, fn ) {
+			return typeof delay === "number" ?
+				this.each(function() {
+					var elem = this;
+					setTimeout(function() {
+						$( elem ).focus();
+						if ( fn ) {
+							fn.call( elem );
+						}
+					}, delay );
+				}) :
+				orig.apply( this, arguments );
+		};
+	})( $.fn.focus ),
+
+	disableSelection: (function() {
+		var eventType = "onselectstart" in document.createElement( "div" ) ?
+			"selectstart" :
+			"mousedown";
+
+		return function() {
+			return this.bind( eventType + ".ui-disableSelection", function( event ) {
+				event.preventDefault();
+			});
+		};
+	})(),
+
+	enableSelection: function() {
+		return this.unbind( ".ui-disableSelection" );
+	},
+
+	zIndex: function( zIndex ) {
+		if ( zIndex !== undefined ) {
+			return this.css( "zIndex", zIndex );
+		}
+
+		if ( this.length ) {
+			var elem = $( this[ 0 ] ), position, value;
+			while ( elem.length && elem[ 0 ] !== document ) {
+				// Ignore z-index if position is set to a value where z-index is ignored by the browser
+				// This makes behavior of this function consistent across browsers
+				// WebKit always returns auto if the element is positioned
+				position = elem.css( "position" );
+				if ( position === "absolute" || position === "relative" || position === "fixed" ) {
+					// IE returns 0 when zIndex is not specified
+					// other browsers return a string
+					// we ignore the case of nested elements with an explicit value of 0
+					// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
+					value = parseInt( elem.css( "zIndex" ), 10 );
+					if ( !isNaN( value ) && value !== 0 ) {
+						return value;
+					}
+				}
+				elem = elem.parent();
+			}
+		}
+
+		return 0;
+	}
+});
+
+// $.ui.plugin is deprecated. Use $.widget() extensions instead.
+$.ui.plugin = {
+	add: function( module, option, set ) {
+		var i,
+			proto = $.ui[ module ].prototype;
+		for ( i in set ) {
+			proto.plugins[ i ] = proto.plugins[ i ] || [];
+			proto.plugins[ i ].push( [ option, set[ i ] ] );
+		}
+	},
+	call: function( instance, name, args, allowDisconnected ) {
+		var i,
+			set = instance.plugins[ name ];
+
+		if ( !set ) {
+			return;
+		}
+
+		if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
+			return;
+		}
+
+		for ( i = 0; i < set.length; i++ ) {
+			if ( instance.options[ set[ i ][ 0 ] ] ) {
+				set[ i ][ 1 ].apply( instance.element, args );
+			}
+		}
+	}
+};
+
+
+/*!
+ * jQuery UI Widget 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/jQuery.widget/
+ */
+
+
+var widget_uuid = 0,
+	widget_slice = Array.prototype.slice;
+
+$.cleanData = (function( orig ) {
+	return function( elems ) {
+		var events, elem, i;
+		for ( i = 0; (elem = elems[i]) != null; i++ ) {
+			try {
+
+				// Only trigger remove when necessary to save time
+				events = $._data( elem, "events" );
+				if ( events && events.remove ) {
+					$( elem ).triggerHandler( "remove" );
+				}
+
+			// http://bugs.jquery.com/ticket/8235
+			} catch ( e ) {}
+		}
+		orig( elems );
+	};
+})( $.cleanData );
+
+$.widget = function( name, base, prototype ) {
+	var fullName, existingConstructor, constructor, basePrototype,
+		// proxiedPrototype allows the provided prototype to remain unmodified
+		// so that it can be used as a mixin for multiple widgets (#8876)
+		proxiedPrototype = {},
+		namespace = name.split( "." )[ 0 ];
+
+	name = name.split( "." )[ 1 ];
+	fullName = namespace + "-" + name;
+
+	if ( !prototype ) {
+		prototype = base;
+		base = $.Widget;
+	}
+
+	// create selector for plugin
+	$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
+		return !!$.data( elem, fullName );
+	};
+
+	$[ namespace ] = $[ namespace ] || {};
+	existingConstructor = $[ namespace ][ name ];
+	constructor = $[ namespace ][ name ] = function( options, element ) {
+		// allow instantiation without "new" keyword
+		if ( !this._createWidget ) {
+			return new constructor( options, element );
+		}
+
+		// allow instantiation without initializing for simple inheritance
+		// must use "new" keyword (the code above always passes args)
+		if ( arguments.length ) {
+			this._createWidget( options, element );
+		}
+	};
+	// extend with the existing constructor to carry over any static properties
+	$.extend( constructor, existingConstructor, {
+		version: prototype.version,
+		// copy the object used to create the prototype in case we need to
+		// redefine the widget later
+		_proto: $.extend( {}, prototype ),
+		// track widgets that inherit from this widget in case this widget is
+		// redefined after a widget inherits from it
+		_childConstructors: []
+	});
+
+	basePrototype = new base();
+	// we need to make the options hash a property directly on the new instance
+	// otherwise we'll modify the options hash on the prototype that we're
+	// inheriting from
+	basePrototype.options = $.widget.extend( {}, basePrototype.options );
+	$.each( prototype, function( prop, value ) {
+		if ( !$.isFunction( value ) ) {
+			proxiedPrototype[ prop ] = value;
+			return;
+		}
+		proxiedPrototype[ prop ] = (function() {
+			var _super = function() {
+					return base.prototype[ prop ].apply( this, arguments );
+				},
+				_superApply = function( args ) {
+					return base.prototype[ prop ].apply( this, args );
+				};
+			return function() {
+				var __super = this._super,
+					__superApply = this._superApply,
+					returnValue;
+
+				this._super = _super;
+				this._superApply = _superApply;
+
+				returnValue = value.apply( this, arguments );
+
+				this._super = __super;
+				this._superApply = __superApply;
+
+				return returnValue;
+			};
+		})();
+	});
+	constructor.prototype = $.widget.extend( basePrototype, {
+		// TODO: remove support for widgetEventPrefix
+		// always use the name + a colon as the prefix, e.g., draggable:start
+		// don't prefix for widgets that aren't DOM-based
+		widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
+	}, proxiedPrototype, {
+		constructor: constructor,
+		namespace: namespace,
+		widgetName: name,
+		widgetFullName: fullName
+	});
+
+	// If this widget is being redefined then we need to find all widgets that
+	// are inheriting from it and redefine all of them so that they inherit from
+	// the new version of this widget. We're essentially trying to replace one
+	// level in the prototype chain.
+	if ( existingConstructor ) {
+		$.each( existingConstructor._childConstructors, function( i, child ) {
+			var childPrototype = child.prototype;
+
+			// redefine the child widget using the same prototype that was
+			// originally used, but inherit from the new version of the base
+			$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
+		});
+		// remove the list of existing child constructors from the old constructor
+		// so the old child constructors can be garbage collected
+		delete existingConstructor._childConstructors;
+	} else {
+		base._childConstructors.push( constructor );
+	}
+
+	$.widget.bridge( name, constructor );
+
+	return constructor;
+};
+
+$.widget.extend = function( target ) {
+	var input = widget_slice.call( arguments, 1 ),
+		inputIndex = 0,
+		inputLength = input.length,
+		key,
+		value;
+	for ( ; inputIndex < inputLength; inputIndex++ ) {
+		for ( key in input[ inputIndex ] ) {
+			value = input[ inputIndex ][ key ];
+			if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
+				// Clone objects
+				if ( $.isPlainObject( value ) ) {
+					target[ key ] = $.isPlainObject( target[ key ] ) ?
+						$.widget.extend( {}, target[ key ], value ) :
+						// Don't extend strings, arrays, etc. with objects
+						$.widget.extend( {}, value );
+				// Copy everything else by reference
+				} else {
+					target[ key ] = value;
+				}
+			}
+		}
+	}
+	return target;
+};
+
+$.widget.bridge = function( name, object ) {
+	var fullName = object.prototype.widgetFullName || name;
+	$.fn[ name ] = function( options ) {
+		var isMethodCall = typeof options === "string",
+			args = widget_slice.call( arguments, 1 ),
+			returnValue = this;
+
+		if ( isMethodCall ) {
+			this.each(function() {
+				var methodValue,
+					instance = $.data( this, fullName );
+				if ( options === "instance" ) {
+					returnValue = instance;
+					return false;
+				}
+				if ( !instance ) {
+					return $.error( "cannot call methods on " + name + " prior to initialization; " +
+						"attempted to call method '" + options + "'" );
+				}
+				if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
+					return $.error( "no such method '" + options + "' for " + name + " widget instance" );
+				}
+				methodValue = instance[ options ].apply( instance, args );
+				if ( methodValue !== instance && methodValue !== undefined ) {
+					returnValue = methodValue && methodValue.jquery ?
+						returnValue.pushStack( methodValue.get() ) :
+						methodValue;
+					return false;
+				}
+			});
+		} else {
+
+			// Allow multiple hashes to be passed on init
+			if ( args.length ) {
+				options = $.widget.extend.apply( null, [ options ].concat(args) );
+			}
+
+			this.each(function() {
+				var instance = $.data( this, fullName );
+				if ( instance ) {
+					instance.option( options || {} );
+					if ( instance._init ) {
+						instance._init();
+					}
+				} else {
+					$.data( this, fullName, new object( options, this ) );
+				}
+			});
+		}
+
+		return returnValue;
+	};
+};
+
+$.Widget = function( /* options, element */ ) {};
+$.Widget._childConstructors = [];
+
+$.Widget.prototype = {
+	widgetName: "widget",
+	widgetEventPrefix: "",
+	defaultElement: "<div>",
+	options: {
+		disabled: false,
+
+		// callbacks
+		create: null
+	},
+	_createWidget: function( options, element ) {
+		element = $( element || this.defaultElement || this )[ 0 ];
+		this.element = $( element );
+		this.uuid = widget_uuid++;
+		this.eventNamespace = "." + this.widgetName + this.uuid;
+
+		this.bindings = $();
+		this.hoverable = $();
+		this.focusable = $();
+
+		if ( element !== this ) {
+			$.data( element, this.widgetFullName, this );
+			this._on( true, this.element, {
+				remove: function( event ) {
+					if ( event.target === element ) {
+						this.destroy();
+					}
+				}
+			});
+			this.document = $( element.style ?
+				// element within the document
+				element.ownerDocument :
+				// element is window or document
+				element.document || element );
+			this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
+		}
+
+		this.options = $.widget.extend( {},
+			this.options,
+			this._getCreateOptions(),
+			options );
+
+		this._create();
+		this._trigger( "create", null, this._getCreateEventData() );
+		this._init();
+	},
+	_getCreateOptions: $.noop,
+	_getCreateEventData: $.noop,
+	_create: $.noop,
+	_init: $.noop,
+
+	destroy: function() {
+		this._destroy();
+		// we can probably remove the unbind calls in 2.0
+		// all event bindings should go through this._on()
+		this.element
+			.unbind( this.eventNamespace )
+			.removeData( this.widgetFullName )
+			// support: jquery <1.6.3
+			// http://bugs.jquery.com/ticket/9413
+			.removeData( $.camelCase( this.widgetFullName ) );
+		this.widget()
+			.unbind( this.eventNamespace )
+			.removeAttr( "aria-disabled" )
+			.removeClass(
+				this.widgetFullName + "-disabled " +
+				"ui-state-disabled" );
+
+		// clean up events and states
+		this.bindings.unbind( this.eventNamespace );
+		this.hoverable.removeClass( "ui-state-hover" );
+		this.focusable.removeClass( "ui-state-focus" );
+	},
+	_destroy: $.noop,
+
+	widget: function() {
+		return this.element;
+	},
+
+	option: function( key, value ) {
+		var options = key,
+			parts,
+			curOption,
+			i;
+
+		if ( arguments.length === 0 ) {
+			// don't return a reference to the internal hash
+			return $.widget.extend( {}, this.options );
+		}
+
+		if ( typeof key === "string" ) {
+			// handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+			options = {};
+			parts = key.split( "." );
+			key = parts.shift();
+			if ( parts.length ) {
+				curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+				for ( i = 0; i < parts.length - 1; i++ ) {
+					curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+					curOption = curOption[ parts[ i ] ];
+				}
+				key = parts.pop();
+				if ( arguments.length === 1 ) {
+					return curOption[ key ] === undefined ? null : curOption[ key ];
+				}
+				curOption[ key ] = value;
+			} else {
+				if ( arguments.length === 1 ) {
+					return this.options[ key ] === undefined ? null : this.options[ key ];
+				}
+				options[ key ] = value;
+			}
+		}
+
+		this._setOptions( options );
+
+		return this;
+	},
+	_setOptions: function( options ) {
+		var key;
+
+		for ( key in options ) {
+			this._setOption( key, options[ key ] );
+		}
+
+		return this;
+	},
+	_setOption: function( key, value ) {
+		this.options[ key ] = value;
+
+		if ( key === "disabled" ) {
+			this.widget()
+				.toggleClass( this.widgetFullName + "-disabled", !!value );
+
+			// If the widget is becoming disabled, then nothing is interactive
+			if ( value ) {
+				this.hoverable.removeClass( "ui-state-hover" );
+				this.focusable.removeClass( "ui-state-focus" );
+			}
+		}
+
+		return this;
+	},
+
+	enable: function() {
+		return this._setOptions({ disabled: false });
+	},
+	disable: function() {
+		return this._setOptions({ disabled: true });
+	},
+
+	_on: function( suppressDisabledCheck, element, handlers ) {
+		var delegateElement,
+			instance = this;
+
+		// no suppressDisabledCheck flag, shuffle arguments
+		if ( typeof suppressDisabledCheck !== "boolean" ) {
+			handlers = element;
+			element = suppressDisabledCheck;
+			suppressDisabledCheck = false;
+		}
+
+		// no element argument, shuffle and use this.element
+		if ( !handlers ) {
+			handlers = element;
+			element = this.element;
+			delegateElement = this.widget();
+		} else {
+			element = delegateElement = $( element );
+			this.bindings = this.bindings.add( element );
+		}
+
+		$.each( handlers, function( event, handler ) {
+			function handlerProxy() {
+				// allow widgets to customize the disabled handling
+				// - disabled as an array instead of boolean
+				// - disabled class as method for disabling individual parts
+				if ( !suppressDisabledCheck &&
+						( instance.options.disabled === true ||
+							$( this ).hasClass( "ui-state-disabled" ) ) ) {
+					return;
+				}
+				return ( typeof handler === "string" ? instance[ handler ] : handler )
+					.apply( instance, arguments );
+			}
+
+			// copy the guid so direct unbinding works
+			if ( typeof handler !== "string" ) {
+				handlerProxy.guid = handler.guid =
+					handler.guid || handlerProxy.guid || $.guid++;
+			}
+
+			var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
+				eventName = match[1] + instance.eventNamespace,
+				selector = match[2];
+			if ( selector ) {
+				delegateElement.delegate( selector, eventName, handlerProxy );
+			} else {
+				element.bind( eventName, handlerProxy );
+			}
+		});
+	},
+
+	_off: function( element, eventName ) {
+		eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
+			this.eventNamespace;
+		element.unbind( eventName ).undelegate( eventName );
+
+		// Clear the stack to avoid memory leaks (#10056)
+		this.bindings = $( this.bindings.not( element ).get() );
+		this.focusable = $( this.focusable.not( element ).get() );
+		this.hoverable = $( this.hoverable.not( element ).get() );
+	},
+
+	_delay: function( handler, delay ) {
+		function handlerProxy() {
+			return ( typeof handler === "string" ? instance[ handler ] : handler )
+				.apply( instance, arguments );
+		}
+		var instance = this;
+		return setTimeout( handlerProxy, delay || 0 );
+	},
+
+	_hoverable: function( element ) {
+		this.hoverable = this.hoverable.add( element );
+		this._on( element, {
+			mouseenter: function( event ) {
+				$( event.currentTarget ).addClass( "ui-state-hover" );
+			},
+			mouseleave: function( event ) {
+				$( event.currentTarget ).removeClass( "ui-state-hover" );
+			}
+		});
+	},
+
+	_focusable: function( element ) {
+		this.focusable = this.focusable.add( element );
+		this._on( element, {
+			focusin: function( event ) {
+				$( event.currentTarget ).addClass( "ui-state-focus" );
+			},
+			focusout: function( event ) {
+				$( event.currentTarget ).removeClass( "ui-state-focus" );
+			}
+		});
+	},
+
+	_trigger: function( type, event, data ) {
+		var prop, orig,
+			callback = this.options[ type ];
+
+		data = data || {};
+		event = $.Event( event );
+		event.type = ( type === this.widgetEventPrefix ?
+			type :
+			this.widgetEventPrefix + type ).toLowerCase();
+		// the original event may come from any element
+		// so we need to reset the target on the new event
+		event.target = this.element[ 0 ];
+
+		// copy original event properties over to the new event
+		orig = event.originalEvent;
+		if ( orig ) {
+			for ( prop in orig ) {
+				if ( !( prop in event ) ) {
+					event[ prop ] = orig[ prop ];
+				}
+			}
+		}
+
+		this.element.trigger( event, data );
+		return !( $.isFunction( callback ) &&
+			callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
+			event.isDefaultPrevented() );
+	}
+};
+
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+	$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+		if ( typeof options === "string" ) {
+			options = { effect: options };
+		}
+		var hasOptions,
+			effectName = !options ?
+				method :
+				options === true || typeof options === "number" ?
+					defaultEffect :
+					options.effect || defaultEffect;
+		options = options || {};
+		if ( typeof options === "number" ) {
+			options = { duration: options };
+		}
+		hasOptions = !$.isEmptyObject( options );
+		options.complete = callback;
+		if ( options.delay ) {
+			element.delay( options.delay );
+		}
+		if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
+			element[ method ]( options );
+		} else if ( effectName !== method && element[ effectName ] ) {
+			element[ effectName ]( options.duration, options.easing, callback );
+		} else {
+			element.queue(function( next ) {
+				$( this )[ method ]();
+				if ( callback ) {
+					callback.call( element[ 0 ] );
+				}
+				next();
+			});
+		}
+	};
+});
+
+var widget = $.widget;
+
+
+/*!
+ * jQuery UI Mouse 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/mouse/
+ */
+
+
+var mouseHandled = false;
+$( document ).mouseup( function() {
+	mouseHandled = false;
+});
+
+var mouse = $.widget("ui.mouse", {
+	version: "1.11.4",
+	options: {
+		cancel: "input,textarea,button,select,option",
+		distance: 1,
+		delay: 0
+	},
+	_mouseInit: function() {
+		var that = this;
+
+		this.element
+			.bind("mousedown." + this.widgetName, function(event) {
+				return that._mouseDown(event);
+			})
+			.bind("click." + this.widgetName, function(event) {
+				if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
+					$.removeData(event.target, that.widgetName + ".preventClickEvent");
+					event.stopImmediatePropagation();
+					return false;
+				}
+			});
+
+		this.started = false;
+	},
+
+	// TODO: make sure destroying one instance of mouse doesn't mess with
+	// other instances of mouse
+	_mouseDestroy: function() {
+		this.element.unbind("." + this.widgetName);
+		if ( this._mouseMoveDelegate ) {
+			this.document
+				.unbind("mousemove." + this.widgetName, this._mouseMoveDelegate)
+				.unbind("mouseup." + this.widgetName, this._mouseUpDelegate);
+		}
+	},
+
+	_mouseDown: function(event) {
+		// don't let more than one widget handle mouseStart
+		if ( mouseHandled ) {
+			return;
+		}
+
+		this._mouseMoved = false;
+
+		// we may have missed mouseup (out of window)
+		(this._mouseStarted && this._mouseUp(event));
+
+		this._mouseDownEvent = event;
+
+		var that = this,
+			btnIsLeft = (event.which === 1),
+			// event.target.nodeName works around a bug in IE 8 with
+			// disabled inputs (#7620)
+			elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
+		if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
+			return true;
+		}
+
+		this.mouseDelayMet = !this.options.delay;
+		if (!this.mouseDelayMet) {
+			this._mouseDelayTimer = setTimeout(function() {
+				that.mouseDelayMet = true;
+			}, this.options.delay);
+		}
+
+		if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+			this._mouseStarted = (this._mouseStart(event) !== false);
+			if (!this._mouseStarted) {
+				event.preventDefault();
+				return true;
+			}
+		}
+
+		// Click event may never have fired (Gecko & Opera)
+		if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
+			$.removeData(event.target, this.widgetName + ".preventClickEvent");
+		}
+
+		// these delegates are required to keep context
+		this._mouseMoveDelegate = function(event) {
+			return that._mouseMove(event);
+		};
+		this._mouseUpDelegate = function(event) {
+			return that._mouseUp(event);
+		};
+
+		this.document
+			.bind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
+			.bind( "mouseup." + this.widgetName, this._mouseUpDelegate );
+
+		event.preventDefault();
+
+		mouseHandled = true;
+		return true;
+	},
+
+	_mouseMove: function(event) {
+		// Only check for mouseups outside the document if you've moved inside the document
+		// at least once. This prevents the firing of mouseup in the case of IE<9, which will
+		// fire a mousemove event if content is placed under the cursor. See #7778
+		// Support: IE <9
+		if ( this._mouseMoved ) {
+			// IE mouseup check - mouseup happened when mouse was out of window
+			if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
+				return this._mouseUp(event);
+
+			// Iframe mouseup check - mouseup occurred in another document
+			} else if ( !event.which ) {
+				return this._mouseUp( event );
+			}
+		}
+
+		if ( event.which || event.button ) {
+			this._mouseMoved = true;
+		}
+
+		if (this._mouseStarted) {
+			this._mouseDrag(event);
+			return event.preventDefault();
+		}
+
+		if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+			this._mouseStarted =
+				(this._mouseStart(this._mouseDownEvent, event) !== false);
+			(this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
+		}
+
+		return !this._mouseStarted;
+	},
+
+	_mouseUp: function(event) {
+		this.document
+			.unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
+			.unbind( "mouseup." + this.widgetName, this._mouseUpDelegate );
+
+		if (this._mouseStarted) {
+			this._mouseStarted = false;
+
+			if (event.target === this._mouseDownEvent.target) {
+				$.data(event.target, this.widgetName + ".preventClickEvent", true);
+			}
+
+			this._mouseStop(event);
+		}
+
+		mouseHandled = false;
+		return false;
+	},
+
+	_mouseDistanceMet: function(event) {
+		return (Math.max(
+				Math.abs(this._mouseDownEvent.pageX - event.pageX),
+				Math.abs(this._mouseDownEvent.pageY - event.pageY)
+			) >= this.options.distance
+		);
+	},
+
+	_mouseDelayMet: function(/* event */) {
+		return this.mouseDelayMet;
+	},
+
+	// These are placeholder methods, to be overriden by extending plugin
+	_mouseStart: function(/* event */) {},
+	_mouseDrag: function(/* event */) {},
+	_mouseStop: function(/* event */) {},
+	_mouseCapture: function(/* event */) { return true; }
+});
+
+
+/*!
+ * jQuery UI Position 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/position/
+ */
+
+(function() {
+
+$.ui = $.ui || {};
+
+var cachedScrollbarWidth, supportsOffsetFractions,
+	max = Math.max,
+	abs = Math.abs,
+	round = Math.round,
+	rhorizontal = /left|center|right/,
+	rvertical = /top|center|bottom/,
+	roffset = /[\+\-]\d+(\.[\d]+)?%?/,
+	rposition = /^\w+/,
+	rpercent = /%$/,
+	_position = $.fn.position;
+
+function getOffsets( offsets, width, height ) {
+	return [
+		parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
+		parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
+	];
+}
+
+function parseCss( element, property ) {
+	return parseInt( $.css( element, property ), 10 ) || 0;
+}
+
+function getDimensions( elem ) {
+	var raw = elem[0];
+	if ( raw.nodeType === 9 ) {
+		return {
+			width: elem.width(),
+			height: elem.height(),
+			offset: { top: 0, left: 0 }
+		};
+	}
+	if ( $.isWindow( raw ) ) {
+		return {
+			width: elem.width(),
+			height: elem.height(),
+			offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
+		};
+	}
+	if ( raw.preventDefault ) {
+		return {
+			width: 0,
+			height: 0,
+			offset: { top: raw.pageY, left: raw.pageX }
+		};
+	}
+	return {
+		width: elem.outerWidth(),
+		height: elem.outerHeight(),
+		offset: elem.offset()
+	};
+}
+
+$.position = {
+	scrollbarWidth: function() {
+		if ( cachedScrollbarWidth !== undefined ) {
+			return cachedScrollbarWidth;
+		}
+		var w1, w2,
+			div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
+			innerDiv = div.children()[0];
+
+		$( "body" ).append( div );
+		w1 = innerDiv.offsetWidth;
+		div.css( "overflow", "scroll" );
+
+		w2 = innerDiv.offsetWidth;
+
+		if ( w1 === w2 ) {
+			w2 = div[0].clientWidth;
+		}
+
+		div.remove();
+
+		return (cachedScrollbarWidth = w1 - w2);
+	},
+	getScrollInfo: function( within ) {
+		var overflowX = within.isWindow || within.isDocument ? "" :
+				within.element.css( "overflow-x" ),
+			overflowY = within.isWindow || within.isDocument ? "" :
+				within.element.css( "overflow-y" ),
+			hasOverflowX = overflowX === "scroll" ||
+				( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
+			hasOverflowY = overflowY === "scroll" ||
+				( overflowY === "auto" && within.height < within.element[0].scrollHeight );
+		return {
+			width: hasOverflowY ? $.position.scrollbarWidth() : 0,
+			height: hasOverflowX ? $.position.scrollbarWidth() : 0
+		};
+	},
+	getWithinInfo: function( element ) {
+		var withinElement = $( element || window ),
+			isWindow = $.isWindow( withinElement[0] ),
+			isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
+		return {
+			element: withinElement,
+			isWindow: isWindow,
+			isDocument: isDocument,
+			offset: withinElement.offset() || { left: 0, top: 0 },
+			scrollLeft: withinElement.scrollLeft(),
+			scrollTop: withinElement.scrollTop(),
+
+			// support: jQuery 1.6.x
+			// jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows
+			width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(),
+			height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight()
+		};
+	}
+};
+
+$.fn.position = function( options ) {
+	if ( !options || !options.of ) {
+		return _position.apply( this, arguments );
+	}
+
+	// make a copy, we don't want to modify arguments
+	options = $.extend( {}, options );
+
+	var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
+		target = $( options.of ),
+		within = $.position.getWithinInfo( options.within ),
+		scrollInfo = $.position.getScrollInfo( within ),
+		collision = ( options.collision || "flip" ).split( " " ),
+		offsets = {};
+
+	dimensions = getDimensions( target );
+	if ( target[0].preventDefault ) {
+		// force left top to allow flipping
+		options.at = "left top";
+	}
+	targetWidth = dimensions.width;
+	targetHeight = dimensions.height;
+	targetOffset = dimensions.offset;
+	// clone to reuse original targetOffset later
+	basePosition = $.extend( {}, targetOffset );
+
+	// force my and at to have valid horizontal and vertical positions
+	// if a value is missing or invalid, it will be converted to center
+	$.each( [ "my", "at" ], function() {
+		var pos = ( options[ this ] || "" ).split( " " ),
+			horizontalOffset,
+			verticalOffset;
+
+		if ( pos.length === 1) {
+			pos = rhorizontal.test( pos[ 0 ] ) ?
+				pos.concat( [ "center" ] ) :
+				rvertical.test( pos[ 0 ] ) ?
+					[ "center" ].concat( pos ) :
+					[ "center", "center" ];
+		}
+		pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
+		pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
+
+		// calculate offsets
+		horizontalOffset = roffset.exec( pos[ 0 ] );
+		verticalOffset = roffset.exec( pos[ 1 ] );
+		offsets[ this ] = [
+			horizontalOffset ? horizontalOffset[ 0 ] : 0,
+			verticalOffset ? verticalOffset[ 0 ] : 0
+		];
+
+		// reduce to just the positions without the offsets
+		options[ this ] = [
+			rposition.exec( pos[ 0 ] )[ 0 ],
+			rposition.exec( pos[ 1 ] )[ 0 ]
+		];
+	});
+
+	// normalize collision option
+	if ( collision.length === 1 ) {
+		collision[ 1 ] = collision[ 0 ];
+	}
+
+	if ( options.at[ 0 ] === "right" ) {
+		basePosition.left += targetWidth;
+	} else if ( options.at[ 0 ] === "center" ) {
+		basePosition.left += targetWidth / 2;
+	}
+
+	if ( options.at[ 1 ] === "bottom" ) {
+		basePosition.top += targetHeight;
+	} else if ( options.at[ 1 ] === "center" ) {
+		basePosition.top += targetHeight / 2;
+	}
+
+	atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
+	basePosition.left += atOffset[ 0 ];
+	basePosition.top += atOffset[ 1 ];
+
+	return this.each(function() {
+		var collisionPosition, using,
+			elem = $( this ),
+			elemWidth = elem.outerWidth(),
+			elemHeight = elem.outerHeight(),
+			marginLeft = parseCss( this, "marginLeft" ),
+			marginTop = parseCss( this, "marginTop" ),
+			collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
+			collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
+			position = $.extend( {}, basePosition ),
+			myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
+
+		if ( options.my[ 0 ] === "right" ) {
+			position.left -= elemWidth;
+		} else if ( options.my[ 0 ] === "center" ) {
+			position.left -= elemWidth / 2;
+		}
+
+		if ( options.my[ 1 ] === "bottom" ) {
+			position.top -= elemHeight;
+		} else if ( options.my[ 1 ] === "center" ) {
+			position.top -= elemHeight / 2;
+		}
+
+		position.left += myOffset[ 0 ];
+		position.top += myOffset[ 1 ];
+
+		// if the browser doesn't support fractions, then round for consistent results
+		if ( !supportsOffsetFractions ) {
+			position.left = round( position.left );
+			position.top = round( position.top );
+		}
+
+		collisionPosition = {
+			marginLeft: marginLeft,
+			marginTop: marginTop
+		};
+
+		$.each( [ "left", "top" ], function( i, dir ) {
+			if ( $.ui.position[ collision[ i ] ] ) {
+				$.ui.position[ collision[ i ] ][ dir ]( position, {
+					targetWidth: targetWidth,
+					targetHeight: targetHeight,
+					elemWidth: elemWidth,
+					elemHeight: elemHeight,
+					collisionPosition: collisionPosition,
+					collisionWidth: collisionWidth,
+					collisionHeight: collisionHeight,
+					offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
+					my: options.my,
+					at: options.at,
+					within: within,
+					elem: elem
+				});
+			}
+		});
+
+		if ( options.using ) {
+			// adds feedback as second argument to using callback, if present
+			using = function( props ) {
+				var left = targetOffset.left - position.left,
+					right = left + targetWidth - elemWidth,
+					top = targetOffset.top - position.top,
+					bottom = top + targetHeight - elemHeight,
+					feedback = {
+						target: {
+							element: target,
+							left: targetOffset.left,
+							top: targetOffset.top,
+							width: targetWidth,
+							height: targetHeight
+						},
+						element: {
+							element: elem,
+							left: position.left,
+							top: position.top,
+							width: elemWidth,
+							height: elemHeight
+						},
+						horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
+						vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
+					};
+				if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
+					feedback.horizontal = "center";
+				}
+				if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
+					feedback.vertical = "middle";
+				}
+				if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
+					feedback.important = "horizontal";
+				} else {
+					feedback.important = "vertical";
+				}
+				options.using.call( this, props, feedback );
+			};
+		}
+
+		elem.offset( $.extend( position, { using: using } ) );
+	});
+};
+
+$.ui.position = {
+	fit: {
+		left: function( position, data ) {
+			var within = data.within,
+				withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
+				outerWidth = within.width,
+				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+				overLeft = withinOffset - collisionPosLeft,
+				overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
+				newOverRight;
+
+			// element is wider than within
+			if ( data.collisionWidth > outerWidth ) {
+				// element is initially over the left side of within
+				if ( overLeft > 0 && overRight <= 0 ) {
+					newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
+					position.left += overLeft - newOverRight;
+				// element is initially over right side of within
+				} else if ( overRight > 0 && overLeft <= 0 ) {
+					position.left = withinOffset;
+				// element is initially over both left and right sides of within
+				} else {
+					if ( overLeft > overRight ) {
+						position.left = withinOffset + outerWidth - data.collisionWidth;
+					} else {
+						position.left = withinOffset;
+					}
+				}
+			// too far left -> align with left edge
+			} else if ( overLeft > 0 ) {
+				position.left += overLeft;
+			// too far right -> align with right edge
+			} else if ( overRight > 0 ) {
+				position.left -= overRight;
+			// adjust based on position and margin
+			} else {
+				position.left = max( position.left - collisionPosLeft, position.left );
+			}
+		},
+		top: function( position, data ) {
+			var within = data.within,
+				withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
+				outerHeight = data.within.height,
+				collisionPosTop = position.top - data.collisionPosition.marginTop,
+				overTop = withinOffset - collisionPosTop,
+				overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
+				newOverBottom;
+
+			// element is taller than within
+			if ( data.collisionHeight > outerHeight ) {
+				// element is initially over the top of within
+				if ( overTop > 0 && overBottom <= 0 ) {
+					newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
+					position.top += overTop - newOverBottom;
+				// element is initially over bottom of within
+				} else if ( overBottom > 0 && overTop <= 0 ) {
+					position.top = withinOffset;
+				// element is initially over both top and bottom of within
+				} else {
+					if ( overTop > overBottom ) {
+						position.top = withinOffset + outerHeight - data.collisionHeight;
+					} else {
+						position.top = withinOffset;
+					}
+				}
+			// too far up -> align with top
+			} else if ( overTop > 0 ) {
+				position.top += overTop;
+			// too far down -> align with bottom edge
+			} else if ( overBottom > 0 ) {
+				position.top -= overBottom;
+			// adjust based on position and margin
+			} else {
+				position.top = max( position.top - collisionPosTop, position.top );
+			}
+		}
+	},
+	flip: {
+		left: function( position, data ) {
+			var within = data.within,
+				withinOffset = within.offset.left + within.scrollLeft,
+				outerWidth = within.width,
+				offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
+				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+				overLeft = collisionPosLeft - offsetLeft,
+				overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
+				myOffset = data.my[ 0 ] === "left" ?
+					-data.elemWidth :
+					data.my[ 0 ] === "right" ?
+						data.elemWidth :
+						0,
+				atOffset = data.at[ 0 ] === "left" ?
+					data.targetWidth :
+					data.at[ 0 ] === "right" ?
+						-data.targetWidth :
+						0,
+				offset = -2 * data.offset[ 0 ],
+				newOverRight,
+				newOverLeft;
+
+			if ( overLeft < 0 ) {
+				newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
+				if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
+					position.left += myOffset + atOffset + offset;
+				}
+			} else if ( overRight > 0 ) {
+				newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
+				if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
+					position.left += myOffset + atOffset + offset;
+				}
+			}
+		},
+		top: function( position, data ) {
+			var within = data.within,
+				withinOffset = within.offset.top + within.scrollTop,
+				outerHeight = within.height,
+				offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
+				collisionPosTop = position.top - data.collisionPosition.marginTop,
+				overTop = collisionPosTop - offsetTop,
+				overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
+				top = data.my[ 1 ] === "top",
+				myOffset = top ?
+					-data.elemHeight :
+					data.my[ 1 ] === "bottom" ?
+						data.elemHeight :
+						0,
+				atOffset = data.at[ 1 ] === "top" ?
+					data.targetHeight :
+					data.at[ 1 ] === "bottom" ?
+						-data.targetHeight :
+						0,
+				offset = -2 * data.offset[ 1 ],
+				newOverTop,
+				newOverBottom;
+			if ( overTop < 0 ) {
+				newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
+				if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
+					position.top += myOffset + atOffset + offset;
+				}
+			} else if ( overBottom > 0 ) {
+				newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
+				if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
+					position.top += myOffset + atOffset + offset;
+				}
+			}
+		}
+	},
+	flipfit: {
+		left: function() {
+			$.ui.position.flip.left.apply( this, arguments );
+			$.ui.position.fit.left.apply( this, arguments );
+		},
+		top: function() {
+			$.ui.position.flip.top.apply( this, arguments );
+			$.ui.position.fit.top.apply( this, arguments );
+		}
+	}
+};
+
+// fraction support test
+(function() {
+	var testElement, testElementParent, testElementStyle, offsetLeft, i,
+		body = document.getElementsByTagName( "body" )[ 0 ],
+		div = document.createElement( "div" );
+
+	//Create a "fake body" for testing based on method used in jQuery.support
+	testElement = document.createElement( body ? "div" : "body" );
+	testElementStyle = {
+		visibility: "hidden",
+		width: 0,
+		height: 0,
+		border: 0,
+		margin: 0,
+		background: "none"
+	};
+	if ( body ) {
+		$.extend( testElementStyle, {
+			position: "absolute",
+			left: "-1000px",
+			top: "-1000px"
+		});
+	}
+	for ( i in testElementStyle ) {
+		testElement.style[ i ] = testElementStyle[ i ];
+	}
+	testElement.appendChild( div );
+	testElementParent = body || document.documentElement;
+	testElementParent.insertBefore( testElement, testElementParent.firstChild );
+
+	div.style.cssText = "position: absolute; left: 10.7432222px;";
+
+	offsetLeft = $( div ).offset().left;
+	supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11;
+
+	testElement.innerHTML = "";
+	testElementParent.removeChild( testElement );
+})();
+
+})();
+
+var position = $.ui.position;
+
+
+/*!
+ * jQuery UI Draggable 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/draggable/
+ */
+
+
+$.widget("ui.draggable", $.ui.mouse, {
+	version: "1.11.4",
+	widgetEventPrefix: "drag",
+	options: {
+		addClasses: true,
+		appendTo: "parent",
+		axis: false,
+		connectToSortable: false,
+		containment: false,
+		cursor: "auto",
+		cursorAt: false,
+		grid: false,
+		handle: false,
+		helper: "original",
+		iframeFix: false,
+		opacity: false,
+		refreshPositions: false,
+		revert: false,
+		revertDuration: 500,
+		scope: "default",
+		scroll: true,
+		scrollSensitivity: 20,
+		scrollSpeed: 20,
+		snap: false,
+		snapMode: "both",
+		snapTolerance: 20,
+		stack: false,
+		zIndex: false,
+
+		// callbacks
+		drag: null,
+		start: null,
+		stop: null
+	},
+	_create: function() {
+
+		if ( this.options.helper === "original" ) {
+			this._setPositionRelative();
+		}
+		if (this.options.addClasses){
+			this.element.addClass("ui-draggable");
+		}
+		if (this.options.disabled){
+			this.element.addClass("ui-draggable-disabled");
+		}
+		this._setHandleClassName();
+
+		this._mouseInit();
+	},
+
+	_setOption: function( key, value ) {
+		this._super( key, value );
+		if ( key === "handle" ) {
+			this._removeHandleClassName();
+			this._setHandleClassName();
+		}
+	},
+
+	_destroy: function() {
+		if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
+			this.destroyOnClear = true;
+			return;
+		}
+		this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
+		this._removeHandleClassName();
+		this._mouseDestroy();
+	},
+
+	_mouseCapture: function(event) {
+		var o = this.options;
+
+		this._blurActiveElement( event );
+
+		// among others, prevent a drag on a resizable-handle
+		if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
+			return false;
+		}
+
+		//Quit if we're not on a valid handle
+		this.handle = this._getHandle(event);
+		if (!this.handle) {
+			return false;
+		}
+
+		this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
+
+		return true;
+
+	},
+
+	_blockFrames: function( selector ) {
+		this.iframeBlocks = this.document.find( selector ).map(function() {
+			var iframe = $( this );
+
+			return $( "<div>" )
+				.css( "position", "absolute" )
+				.appendTo( iframe.parent() )
+				.outerWidth( iframe.outerWidth() )
+				.outerHeight( iframe.outerHeight() )
+				.offset( iframe.offset() )[ 0 ];
+		});
+	},
+
+	_unblockFrames: function() {
+		if ( this.iframeBlocks ) {
+			this.iframeBlocks.remove();
+			delete this.iframeBlocks;
+		}
+	},
+
+	_blurActiveElement: function( event ) {
+		var document = this.document[ 0 ];
+
+		// Only need to blur if the event occurred on the draggable itself, see #10527
+		if ( !this.handleElement.is( event.target ) ) {
+			return;
+		}
+
+		// support: IE9
+		// IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
+		try {
+
+			// Support: IE9, IE10
+			// If the <body> is blurred, IE will switch windows, see #9520
+			if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) {
+
+				// Blur any element that currently has focus, see #4261
+				$( document.activeElement ).blur();
+			}
+		} catch ( error ) {}
+	},
+
+	_mouseStart: function(event) {
+
+		var o = this.options;
+
+		//Create and append the visible helper
+		this.helper = this._createHelper(event);
+
+		this.helper.addClass("ui-draggable-dragging");
+
+		//Cache the helper size
+		this._cacheHelperProportions();
+
+		//If ddmanager is used for droppables, set the global draggable
+		if ($.ui.ddmanager) {
+			$.ui.ddmanager.current = this;
+		}
+
+		/*
+		 * - Position generation -
+		 * This block generates everything position related - it's the core of draggables.
+		 */
+
+		//Cache the margins of the original element
+		this._cacheMargins();
+
+		//Store the helper's css position
+		this.cssPosition = this.helper.css( "position" );
+		this.scrollParent = this.helper.scrollParent( true );
+		this.offsetParent = this.helper.offsetParent();
+		this.hasFixedAncestor = this.helper.parents().filter(function() {
+				return $( this ).css( "position" ) === "fixed";
+			}).length > 0;
+
+		//The element's absolute position on the page minus margins
+		this.positionAbs = this.element.offset();
+		this._refreshOffsets( event );
+
+		//Generate the original position
+		this.originalPosition = this.position = this._generatePosition( event, false );
+		this.originalPageX = event.pageX;
+		this.originalPageY = event.pageY;
+
+		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+		(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+		//Set a containment if given in the options
+		this._setContainment();
+
+		//Trigger event + callbacks
+		if (this._trigger("start", event) === false) {
+			this._clear();
+			return false;
+		}
+
+		//Recache the helper size
+		this._cacheHelperProportions();
+
+		//Prepare the droppable offsets
+		if ($.ui.ddmanager && !o.dropBehaviour) {
+			$.ui.ddmanager.prepareOffsets(this, event);
+		}
+
+		// Reset helper's right/bottom css if they're set and set explicit width/height instead
+		// as this prevents resizing of elements with right/bottom set (see #7772)
+		this._normalizeRightBottom();
+
+		this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+
+		//If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
+		if ( $.ui.ddmanager ) {
+			$.ui.ddmanager.dragStart(this, event);
+		}
+
+		return true;
+	},
+
+	_refreshOffsets: function( event ) {
+		this.offset = {
+			top: this.positionAbs.top - this.margins.top,
+			left: this.positionAbs.left - this.margins.left,
+			scroll: false,
+			parent: this._getParentOffset(),
+			relative: this._getRelativeOffset()
+		};
+
+		this.offset.click = {
+			left: event.pageX - this.offset.left,
+			top: event.pageY - this.offset.top
+		};
+	},
+
+	_mouseDrag: function(event, noPropagation) {
+		// reset any necessary cached properties (see #5009)
+		if ( this.hasFixedAncestor ) {
+			this.offset.parent = this._getParentOffset();
+		}
+
+		//Compute the helpers position
+		this.position = this._generatePosition( event, true );
+		this.positionAbs = this._convertPositionTo("absolute");
+
+		//Call plugins and callbacks and use the resulting position if something is returned
+		if (!noPropagation) {
+			var ui = this._uiHash();
+			if (this._trigger("drag", event, ui) === false) {
+				this._mouseUp({});
+				return false;
+			}
+			this.position = ui.position;
+		}
+
+		this.helper[ 0 ].style.left = this.position.left + "px";
+		this.helper[ 0 ].style.top = this.position.top + "px";
+
+		if ($.ui.ddmanager) {
+			$.ui.ddmanager.drag(this, event);
+		}
+
+		return false;
+	},
+
+	_mouseStop: function(event) {
+
+		//If we are using droppables, inform the manager about the drop
+		var that = this,
+			dropped = false;
+		if ($.ui.ddmanager && !this.options.dropBehaviour) {
+			dropped = $.ui.ddmanager.drop(this, event);
+		}
+
+		//if a drop comes from outside (a sortable)
+		if (this.dropped) {
+			dropped = this.dropped;
+			this.dropped = false;
+		}
+
+		if ((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
+			$(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
+				if (that._trigger("stop", event) !== false) {
+					that._clear();
+				}
+			});
+		} else {
+			if (this._trigger("stop", event) !== false) {
+				this._clear();
+			}
+		}
+
+		return false;
+	},
+
+	_mouseUp: function( event ) {
+		this._unblockFrames();
+
+		//If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
+		if ( $.ui.ddmanager ) {
+			$.ui.ddmanager.dragStop(this, event);
+		}
+
+		// Only need to focus if the event occurred on the draggable itself, see #10527
+		if ( this.handleElement.is( event.target ) ) {
+			// The interaction is over; whether or not the click resulted in a drag, focus the element
+			this.element.focus();
+		}
+
+		return $.ui.mouse.prototype._mouseUp.call(this, event);
+	},
+
+	cancel: function() {
+
+		if (this.helper.is(".ui-draggable-dragging")) {
+			this._mouseUp({});
+		} else {
+			this._clear();
+		}
+
+		return this;
+
+	},
+
+	_getHandle: function(event) {
+		return this.options.handle ?
+			!!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
+			true;
+	},
+
+	_setHandleClassName: function() {
+		this.handleElement = this.options.handle ?
+			this.element.find( this.options.handle ) : this.element;
+		this.handleElement.addClass( "ui-draggable-handle" );
+	},
+
+	_removeHandleClassName: function() {
+		this.handleElement.removeClass( "ui-draggable-handle" );
+	},
+
+	_createHelper: function(event) {
+
+		var o = this.options,
+			helperIsFunction = $.isFunction( o.helper ),
+			helper = helperIsFunction ?
+				$( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
+				( o.helper === "clone" ?
+					this.element.clone().removeAttr( "id" ) :
+					this.element );
+
+		if (!helper.parents("body").length) {
+			helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
+		}
+
+		// http://bugs.jqueryui.com/ticket/9446
+		// a helper function can return the original element
+		// which wouldn't have been set to relative in _create
+		if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
+			this._setPositionRelative();
+		}
+
+		if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
+			helper.css("position", "absolute");
+		}
+
+		return helper;
+
+	},
+
+	_setPositionRelative: function() {
+		if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
+			this.element[ 0 ].style.position = "relative";
+		}
+	},
+
+	_adjustOffsetFromHelper: function(obj) {
+		if (typeof obj === "string") {
+			obj = obj.split(" ");
+		}
+		if ($.isArray(obj)) {
+			obj = { left: +obj[0], top: +obj[1] || 0 };
+		}
+		if ("left" in obj) {
+			this.offset.click.left = obj.left + this.margins.left;
+		}
+		if ("right" in obj) {
+			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+		}
+		if ("top" in obj) {
+			this.offset.click.top = obj.top + this.margins.top;
+		}
+		if ("bottom" in obj) {
+			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+		}
+	},
+
+	_isRootNode: function( element ) {
+		return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
+	},
+
+	_getParentOffset: function() {
+
+		//Get the offsetParent and cache its position
+		var po = this.offsetParent.offset(),
+			document = this.document[ 0 ];
+
+		// This is a special case where we need to modify a offset calculated on start, since the following happened:
+		// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+		//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+		if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+			po.left += this.scrollParent.scrollLeft();
+			po.top += this.scrollParent.scrollTop();
+		}
+
+		if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
+			po = { top: 0, left: 0 };
+		}
+
+		return {
+			top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0),
+			left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0)
+		};
+
+	},
+
+	_getRelativeOffset: function() {
+		if ( this.cssPosition !== "relative" ) {
+			return { top: 0, left: 0 };
+		}
+
+		var p = this.element.position(),
+			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
+
+		return {
+			top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
+			left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
+		};
+
+	},
+
+	_cacheMargins: function() {
+		this.margins = {
+			left: (parseInt(this.element.css("marginLeft"), 10) || 0),
+			top: (parseInt(this.element.css("marginTop"), 10) || 0),
+			right: (parseInt(this.element.css("marginRight"), 10) || 0),
+			bottom: (parseInt(this.element.css("marginBottom"), 10) || 0)
+		};
+	},
+
+	_cacheHelperProportions: function() {
+		this.helperProportions = {
+			width: this.helper.outerWidth(),
+			height: this.helper.outerHeight()
+		};
+	},
+
+	_setContainment: function() {
+
+		var isUserScrollable, c, ce,
+			o = this.options,
+			document = this.document[ 0 ];
+
+		this.relativeContainer = null;
+
+		if ( !o.containment ) {
+			this.containment = null;
+			return;
+		}
+
+		if ( o.containment === "window" ) {
+			this.containment = [
+				$( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
+				$( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
+				$( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
+				$( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+			];
+			return;
+		}
+
+		if ( o.containment === "document") {
+			this.containment = [
+				0,
+				0,
+				$( document ).width() - this.helperProportions.width - this.margins.left,
+				( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+			];
+			return;
+		}
+
+		if ( o.containment.constructor === Array ) {
+			this.containment = o.containment;
+			return;
+		}
+
+		if ( o.containment === "parent" ) {
+			o.containment = this.helper[ 0 ].parentNode;
+		}
+
+		c = $( o.containment );
+		ce = c[ 0 ];
+
+		if ( !ce ) {
+			return;
+		}
+
+		isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
+
+		this.containment = [
+			( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
+			( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
+			( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
+				( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
+				( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
+				this.helperProportions.width -
+				this.margins.left -
+				this.margins.right,
+			( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
+				( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
+				( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
+				this.helperProportions.height -
+				this.margins.top -
+				this.margins.bottom
+		];
+		this.relativeContainer = c;
+	},
+
+	_convertPositionTo: function(d, pos) {
+
+		if (!pos) {
+			pos = this.position;
+		}
+
+		var mod = d === "absolute" ? 1 : -1,
+			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
+
+		return {
+			top: (
+				pos.top	+																// The absolute mouse position
+				this.offset.relative.top * mod +										// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.top * mod -										// The offsetParent's offset without borders (offset + border)
+				( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod)
+			),
+			left: (
+				pos.left +																// The absolute mouse position
+				this.offset.relative.left * mod +										// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.left * mod	-										// The offsetParent's offset without borders (offset + border)
+				( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod)
+			)
+		};
+
+	},
+
+	_generatePosition: function( event, constrainPosition ) {
+
+		var containment, co, top, left,
+			o = this.options,
+			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
+			pageX = event.pageX,
+			pageY = event.pageY;
+
+		// Cache the scroll
+		if ( !scrollIsRootNode || !this.offset.scroll ) {
+			this.offset.scroll = {
+				top: this.scrollParent.scrollTop(),
+				left: this.scrollParent.scrollLeft()
+			};
+		}
+
+		/*
+		 * - Position constraining -
+		 * Constrain the position to a mix of grid, containment.
+		 */
+
+		// If we are not dragging yet, we won't check for options
+		if ( constrainPosition ) {
+			if ( this.containment ) {
+				if ( this.relativeContainer ){
+					co = this.relativeContainer.offset();
+					containment = [
+						this.containment[ 0 ] + co.left,
+						this.containment[ 1 ] + co.top,
+						this.containment[ 2 ] + co.left,
+						this.containment[ 3 ] + co.top
+					];
+				} else {
+					containment = this.containment;
+				}
+
+				if (event.pageX - this.offset.click.left < containment[0]) {
+					pageX = containment[0] + this.offset.click.left;
+				}
+				if (event.pageY - this.offset.click.top < containment[1]) {
+					pageY = containment[1] + this.offset.click.top;
+				}
+				if (event.pageX - this.offset.click.left > containment[2]) {
+					pageX = containment[2] + this.offset.click.left;
+				}
+				if (event.pageY - this.offset.click.top > containment[3]) {
+					pageY = containment[3] + this.offset.click.top;
+				}
+			}
+
+			if (o.grid) {
+				//Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
+				top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
+				pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+				left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
+				pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+			}
+
+			if ( o.axis === "y" ) {
+				pageX = this.originalPageX;
+			}
+
+			if ( o.axis === "x" ) {
+				pageY = this.originalPageY;
+			}
+		}
+
+		return {
+			top: (
+				pageY -																	// The absolute mouse position
+				this.offset.click.top	-												// Click offset (relative to the element)
+				this.offset.relative.top -												// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.top +												// The offsetParent's offset without borders (offset + border)
+				( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
+			),
+			left: (
+				pageX -																	// The absolute mouse position
+				this.offset.click.left -												// Click offset (relative to the element)
+				this.offset.relative.left -												// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.left +												// The offsetParent's offset without borders (offset + border)
+				( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
+			)
+		};
+
+	},
+
+	_clear: function() {
+		this.helper.removeClass("ui-draggable-dragging");
+		if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
+			this.helper.remove();
+		}
+		this.helper = null;
+		this.cancelHelperRemoval = false;
+		if ( this.destroyOnClear ) {
+			this.destroy();
+		}
+	},
+
+	_normalizeRightBottom: function() {
+		if ( this.options.axis !== "y" && this.helper.css( "right" ) !== "auto" ) {
+			this.helper.width( this.helper.width() );
+			this.helper.css( "right", "auto" );
+		}
+		if ( this.options.axis !== "x" && this.helper.css( "bottom" ) !== "auto" ) {
+			this.helper.height( this.helper.height() );
+			this.helper.css( "bottom", "auto" );
+		}
+	},
+
+	// From now on bulk stuff - mainly helpers
+
+	_trigger: function( type, event, ui ) {
+		ui = ui || this._uiHash();
+		$.ui.plugin.call( this, type, [ event, ui, this ], true );
+
+		// Absolute position and offset (see #6884 ) have to be recalculated after plugins
+		if ( /^(drag|start|stop)/.test( type ) ) {
+			this.positionAbs = this._convertPositionTo( "absolute" );
+			ui.offset = this.positionAbs;
+		}
+		return $.Widget.prototype._trigger.call( this, type, event, ui );
+	},
+
+	plugins: {},
+
+	_uiHash: function() {
+		return {
+			helper: this.helper,
+			position: this.position,
+			originalPosition: this.originalPosition,
+			offset: this.positionAbs
+		};
+	}
+
+});
+
+$.ui.plugin.add( "draggable", "connectToSortable", {
+	start: function( event, ui, draggable ) {
+		var uiSortable = $.extend( {}, ui, {
+			item: draggable.element
+		});
+
+		draggable.sortables = [];
+		$( draggable.options.connectToSortable ).each(function() {
+			var sortable = $( this ).sortable( "instance" );
+
+			if ( sortable && !sortable.options.disabled ) {
+				draggable.sortables.push( sortable );
+
+				// refreshPositions is called at drag start to refresh the containerCache
+				// which is used in drag. This ensures it's initialized and synchronized
+				// with any changes that might have happened on the page since initialization.
+				sortable.refreshPositions();
+				sortable._trigger("activate", event, uiSortable);
+			}
+		});
+	},
+	stop: function( event, ui, draggable ) {
+		var uiSortable = $.extend( {}, ui, {
+			item: draggable.element
+		});
+
+		draggable.cancelHelperRemoval = false;
+
+		$.each( draggable.sortables, function() {
+			var sortable = this;
+
+			if ( sortable.isOver ) {
+				sortable.isOver = 0;
+
+				// Allow this sortable to handle removing the helper
+				draggable.cancelHelperRemoval = true;
+				sortable.cancelHelperRemoval = false;
+
+				// Use _storedCSS To restore properties in the sortable,
+				// as this also handles revert (#9675) since the draggable
+				// may have modified them in unexpected ways (#8809)
+				sortable._storedCSS = {
+					position: sortable.placeholder.css( "position" ),
+					top: sortable.placeholder.css( "top" ),
+					left: sortable.placeholder.css( "left" )
+				};
+
+				sortable._mouseStop(event);
+
+				// Once drag has ended, the sortable should return to using
+				// its original helper, not the shared helper from draggable
+				sortable.options.helper = sortable.options._helper;
+			} else {
+				// Prevent this Sortable from removing the helper.
+				// However, don't set the draggable to remove the helper
+				// either as another connected Sortable may yet handle the removal.
+				sortable.cancelHelperRemoval = true;
+
+				sortable._trigger( "deactivate", event, uiSortable );
+			}
+		});
+	},
+	drag: function( event, ui, draggable ) {
+		$.each( draggable.sortables, function() {
+			var innermostIntersecting = false,
+				sortable = this;
+
+			// Copy over variables that sortable's _intersectsWith uses
+			sortable.positionAbs = draggable.positionAbs;
+			sortable.helperProportions = draggable.helperProportions;
+			sortable.offset.click = draggable.offset.click;
+
+			if ( sortable._intersectsWith( sortable.containerCache ) ) {
+				innermostIntersecting = true;
+
+				$.each( draggable.sortables, function() {
+					// Copy over variables that sortable's _intersectsWith uses
+					this.positionAbs = draggable.positionAbs;
+					this.helperProportions = draggable.helperProportions;
+					this.offset.click = draggable.offset.click;
+
+					if ( this !== sortable &&
+							this._intersectsWith( this.containerCache ) &&
+							$.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
+						innermostIntersecting = false;
+					}
+
+					return innermostIntersecting;
+				});
+			}
+
+			if ( innermostIntersecting ) {
+				// If it intersects, we use a little isOver variable and set it once,
+				// so that the move-in stuff gets fired only once.
+				if ( !sortable.isOver ) {
+					sortable.isOver = 1;
+
+					// Store draggable's parent in case we need to reappend to it later.
+					draggable._parent = ui.helper.parent();
+
+					sortable.currentItem = ui.helper
+						.appendTo( sortable.element )
+						.data( "ui-sortable-item", true );
+
+					// Store helper option to later restore it
+					sortable.options._helper = sortable.options.helper;
+
+					sortable.options.helper = function() {
+						return ui.helper[ 0 ];
+					};
+
+					// Fire the start events of the sortable with our passed browser event,
+					// and our own helper (so it doesn't create a new one)
+					event.target = sortable.currentItem[ 0 ];
+					sortable._mouseCapture( event, true );
+					sortable._mouseStart( event, true, true );
+
+					// Because the browser event is way off the new appended portlet,
+					// modify necessary variables to reflect the changes
+					sortable.offset.click.top = draggable.offset.click.top;
+					sortable.offset.click.left = draggable.offset.click.left;
+					sortable.offset.parent.left -= draggable.offset.parent.left -
+						sortable.offset.parent.left;
+					sortable.offset.parent.top -= draggable.offset.parent.top -
+						sortable.offset.parent.top;
+
+					draggable._trigger( "toSortable", event );
+
+					// Inform draggable that the helper is in a valid drop zone,
+					// used solely in the revert option to handle "valid/invalid".
+					draggable.dropped = sortable.element;
+
+					// Need to refreshPositions of all sortables in the case that
+					// adding to one sortable changes the location of the other sortables (#9675)
+					$.each( draggable.sortables, function() {
+						this.refreshPositions();
+					});
+
+					// hack so receive/update callbacks work (mostly)
+					draggable.currentItem = draggable.element;
+					sortable.fromOutside = draggable;
+				}
+
+				if ( sortable.currentItem ) {
+					sortable._mouseDrag( event );
+					// Copy the sortable's position because the draggable's can potentially reflect
+					// a relative position, while sortable is always absolute, which the dragged
+					// element has now become. (#8809)
+					ui.position = sortable.position;
+				}
+			} else {
+				// If it doesn't intersect with the sortable, and it intersected before,
+				// we fake the drag stop of the sortable, but make sure it doesn't remove
+				// the helper by using cancelHelperRemoval.
+				if ( sortable.isOver ) {
+
+					sortable.isOver = 0;
+					sortable.cancelHelperRemoval = true;
+
+					// Calling sortable's mouseStop would trigger a revert,
+					// so revert must be temporarily false until after mouseStop is called.
+					sortable.options._revert = sortable.options.revert;
+					sortable.options.revert = false;
+
+					sortable._trigger( "out", event, sortable._uiHash( sortable ) );
+					sortable._mouseStop( event, true );
+
+					// restore sortable behaviors that were modfied
+					// when the draggable entered the sortable area (#9481)
+					sortable.options.revert = sortable.options._revert;
+					sortable.options.helper = sortable.options._helper;
+
+					if ( sortable.placeholder ) {
+						sortable.placeholder.remove();
+					}
+
+					// Restore and recalculate the draggable's offset considering the sortable
+					// may have modified them in unexpected ways. (#8809, #10669)
+					ui.helper.appendTo( draggable._parent );
+					draggable._refreshOffsets( event );
+					ui.position = draggable._generatePosition( event, true );
+
+					draggable._trigger( "fromSortable", event );
+
+					// Inform draggable that the helper is no longer in a valid drop zone
+					draggable.dropped = false;
+
+					// Need to refreshPositions of all sortables just in case removing
+					// from one sortable changes the location of other sortables (#9675)
+					$.each( draggable.sortables, function() {
+						this.refreshPositions();
+					});
+				}
+			}
+		});
+	}
+});
+
+$.ui.plugin.add("draggable", "cursor", {
+	start: function( event, ui, instance ) {
+		var t = $( "body" ),
+			o = instance.options;
+
+		if (t.css("cursor")) {
+			o._cursor = t.css("cursor");
+		}
+		t.css("cursor", o.cursor);
+	},
+	stop: function( event, ui, instance ) {
+		var o = instance.options;
+		if (o._cursor) {
+			$("body").css("cursor", o._cursor);
+		}
+	}
+});
+
+$.ui.plugin.add("draggable", "opacity", {
+	start: function( event, ui, instance ) {
+		var t = $( ui.helper ),
+			o = instance.options;
+		if (t.css("opacity")) {
+			o._opacity = t.css("opacity");
+		}
+		t.css("opacity", o.opacity);
+	},
+	stop: function( event, ui, instance ) {
+		var o = instance.options;
+		if (o._opacity) {
+			$(ui.helper).css("opacity", o._opacity);
+		}
+	}
+});
+
+$.ui.plugin.add("draggable", "scroll", {
+	start: function( event, ui, i ) {
+		if ( !i.scrollParentNotHidden ) {
+			i.scrollParentNotHidden = i.helper.scrollParent( false );
+		}
+
+		if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
+			i.overflowOffset = i.scrollParentNotHidden.offset();
+		}
+	},
+	drag: function( event, ui, i  ) {
+
+		var o = i.options,
+			scrolled = false,
+			scrollParent = i.scrollParentNotHidden[ 0 ],
+			document = i.document[ 0 ];
+
+		if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
+			if ( !o.axis || o.axis !== "x" ) {
+				if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) {
+					scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
+				} else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
+					scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
+				}
+			}
+
+			if ( !o.axis || o.axis !== "y" ) {
+				if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) {
+					scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
+				} else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
+					scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
+				}
+			}
+
+		} else {
+
+			if (!o.axis || o.axis !== "x") {
+				if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
+					scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+				} else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
+					scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+				}
+			}
+
+			if (!o.axis || o.axis !== "y") {
+				if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
+					scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+				} else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
+					scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+				}
+			}
+
+		}
+
+		if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+			$.ui.ddmanager.prepareOffsets(i, event);
+		}
+
+	}
+});
+
+$.ui.plugin.add("draggable", "snap", {
+	start: function( event, ui, i ) {
+
+		var o = i.options;
+
+		i.snapElements = [];
+
+		$(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
+			var $t = $(this),
+				$o = $t.offset();
+			if (this !== i.element[0]) {
+				i.snapElements.push({
+					item: this,
+					width: $t.outerWidth(), height: $t.outerHeight(),
+					top: $o.top, left: $o.left
+				});
+			}
+		});
+
+	},
+	drag: function( event, ui, inst ) {
+
+		var ts, bs, ls, rs, l, r, t, b, i, first,
+			o = inst.options,
+			d = o.snapTolerance,
+			x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
+			y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
+
+		for (i = inst.snapElements.length - 1; i >= 0; i--){
+
+			l = inst.snapElements[i].left - inst.margins.left;
+			r = l + inst.snapElements[i].width;
+			t = inst.snapElements[i].top - inst.margins.top;
+			b = t + inst.snapElements[i].height;
+
+			if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
+				if (inst.snapElements[i].snapping) {
+					(inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+				}
+				inst.snapElements[i].snapping = false;
+				continue;
+			}
+
+			if (o.snapMode !== "inner") {
+				ts = Math.abs(t - y2) <= d;
+				bs = Math.abs(b - y1) <= d;
+				ls = Math.abs(l - x2) <= d;
+				rs = Math.abs(r - x1) <= d;
+				if (ts) {
+					ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
+				}
+				if (bs) {
+					ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
+				}
+				if (ls) {
+					ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
+				}
+				if (rs) {
+					ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
+				}
+			}
+
+			first = (ts || bs || ls || rs);
+
+			if (o.snapMode !== "outer") {
+				ts = Math.abs(t - y1) <= d;
+				bs = Math.abs(b - y2) <= d;
+				ls = Math.abs(l - x1) <= d;
+				rs = Math.abs(r - x2) <= d;
+				if (ts) {
+					ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
+				}
+				if (bs) {
+					ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
+				}
+				if (ls) {
+					ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
+				}
+				if (rs) {
+					ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
+				}
+			}
+
+			if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
+				(inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+			}
+			inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
+
+		}
+
+	}
+});
+
+$.ui.plugin.add("draggable", "stack", {
+	start: function( event, ui, instance ) {
+		var min,
+			o = instance.options,
+			group = $.makeArray($(o.stack)).sort(function(a, b) {
+				return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0);
+			});
+
+		if (!group.length) { return; }
+
+		min = parseInt($(group[0]).css("zIndex"), 10) || 0;
+		$(group).each(function(i) {
+			$(this).css("zIndex", min + i);
+		});
+		this.css("zIndex", (min + group.length));
+	}
+});
+
+$.ui.plugin.add("draggable", "zIndex", {
+	start: function( event, ui, instance ) {
+		var t = $( ui.helper ),
+			o = instance.options;
+
+		if (t.css("zIndex")) {
+			o._zIndex = t.css("zIndex");
+		}
+		t.css("zIndex", o.zIndex);
+	},
+	stop: function( event, ui, instance ) {
+		var o = instance.options;
+
+		if (o._zIndex) {
+			$(ui.helper).css("zIndex", o._zIndex);
+		}
+	}
+});
+
+var draggable = $.ui.draggable;
+
+
+/*!
+ * jQuery UI Droppable 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/droppable/
+ */
+
+
+$.widget( "ui.droppable", {
+	version: "1.11.4",
+	widgetEventPrefix: "drop",
+	options: {
+		accept: "*",
+		activeClass: false,
+		addClasses: true,
+		greedy: false,
+		hoverClass: false,
+		scope: "default",
+		tolerance: "intersect",
+
+		// callbacks
+		activate: null,
+		deactivate: null,
+		drop: null,
+		out: null,
+		over: null
+	},
+	_create: function() {
+
+		var proportions,
+			o = this.options,
+			accept = o.accept;
+
+		this.isover = false;
+		this.isout = true;
+
+		this.accept = $.isFunction( accept ) ? accept : function( d ) {
+			return d.is( accept );
+		};
+
+		this.proportions = function( /* valueToWrite */ ) {
+			if ( arguments.length ) {
+				// Store the droppable's proportions
+				proportions = arguments[ 0 ];
+			} else {
+				// Retrieve or derive the droppable's proportions
+				return proportions ?
+					proportions :
+					proportions = {
+						width: this.element[ 0 ].offsetWidth,
+						height: this.element[ 0 ].offsetHeight
+					};
+			}
+		};
+
+		this._addToManager( o.scope );
+
+		o.addClasses && this.element.addClass( "ui-droppable" );
+
+	},
+
+	_addToManager: function( scope ) {
+		// Add the reference and positions to the manager
+		$.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
+		$.ui.ddmanager.droppables[ scope ].push( this );
+	},
+
+	_splice: function( drop ) {
+		var i = 0;
+		for ( ; i < drop.length; i++ ) {
+			if ( drop[ i ] === this ) {
+				drop.splice( i, 1 );
+			}
+		}
+	},
+
+	_destroy: function() {
+		var drop = $.ui.ddmanager.droppables[ this.options.scope ];
+
+		this._splice( drop );
+
+		this.element.removeClass( "ui-droppable ui-droppable-disabled" );
+	},
+
+	_setOption: function( key, value ) {
+
+		if ( key === "accept" ) {
+			this.accept = $.isFunction( value ) ? value : function( d ) {
+				return d.is( value );
+			};
+		} else if ( key === "scope" ) {
+			var drop = $.ui.ddmanager.droppables[ this.options.scope ];
+
+			this._splice( drop );
+			this._addToManager( value );
+		}
+
+		this._super( key, value );
+	},
+
+	_activate: function( event ) {
+		var draggable = $.ui.ddmanager.current;
+		if ( this.options.activeClass ) {
+			this.element.addClass( this.options.activeClass );
+		}
+		if ( draggable ){
+			this._trigger( "activate", event, this.ui( draggable ) );
+		}
+	},
+
+	_deactivate: function( event ) {
+		var draggable = $.ui.ddmanager.current;
+		if ( this.options.activeClass ) {
+			this.element.removeClass( this.options.activeClass );
+		}
+		if ( draggable ){
+			this._trigger( "deactivate", event, this.ui( draggable ) );
+		}
+	},
+
+	_over: function( event ) {
+
+		var draggable = $.ui.ddmanager.current;
+
+		// Bail if draggable and droppable are same element
+		if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
+			return;
+		}
+
+		if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
+			if ( this.options.hoverClass ) {
+				this.element.addClass( this.options.hoverClass );
+			}
+			this._trigger( "over", event, this.ui( draggable ) );
+		}
+
+	},
+
+	_out: function( event ) {
+
+		var draggable = $.ui.ddmanager.current;
+
+		// Bail if draggable and droppable are same element
+		if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
+			return;
+		}
+
+		if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
+			if ( this.options.hoverClass ) {
+				this.element.removeClass( this.options.hoverClass );
+			}
+			this._trigger( "out", event, this.ui( draggable ) );
+		}
+
+	},
+
+	_drop: function( event, custom ) {
+
+		var draggable = custom || $.ui.ddmanager.current,
+			childrenIntersection = false;
+
+		// Bail if draggable and droppable are same element
+		if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
+			return false;
+		}
+
+		this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() {
+			var inst = $( this ).droppable( "instance" );
+			if (
+				inst.options.greedy &&
+				!inst.options.disabled &&
+				inst.options.scope === draggable.options.scope &&
+				inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) &&
+				$.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event )
+			) { childrenIntersection = true; return false; }
+		});
+		if ( childrenIntersection ) {
+			return false;
+		}
+
+		if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
+			if ( this.options.activeClass ) {
+				this.element.removeClass( this.options.activeClass );
+			}
+			if ( this.options.hoverClass ) {
+				this.element.removeClass( this.options.hoverClass );
+			}
+			this._trigger( "drop", event, this.ui( draggable ) );
+			return this.element;
+		}
+
+		return false;
+
+	},
+
+	ui: function( c ) {
+		return {
+			draggable: ( c.currentItem || c.element ),
+			helper: c.helper,
+			position: c.position,
+			offset: c.positionAbs
+		};
+	}
+
+});
+
+$.ui.intersect = (function() {
+	function isOverAxis( x, reference, size ) {
+		return ( x >= reference ) && ( x < ( reference + size ) );
+	}
+
+	return function( draggable, droppable, toleranceMode, event ) {
+
+		if ( !droppable.offset ) {
+			return false;
+		}
+
+		var x1 = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left,
+			y1 = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top,
+			x2 = x1 + draggable.helperProportions.width,
+			y2 = y1 + draggable.helperProportions.height,
+			l = droppable.offset.left,
+			t = droppable.offset.top,
+			r = l + droppable.proportions().width,
+			b = t + droppable.proportions().height;
+
+		switch ( toleranceMode ) {
+		case "fit":
+			return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
+		case "intersect":
+			return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
+				x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
+				t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
+				y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
+		case "pointer":
+			return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width );
+		case "touch":
+			return (
+				( y1 >= t && y1 <= b ) || // Top edge touching
+				( y2 >= t && y2 <= b ) || // Bottom edge touching
+				( y1 < t && y2 > b ) // Surrounded vertically
+			) && (
+				( x1 >= l && x1 <= r ) || // Left edge touching
+				( x2 >= l && x2 <= r ) || // Right edge touching
+				( x1 < l && x2 > r ) // Surrounded horizontally
+			);
+		default:
+			return false;
+		}
+	};
+})();
+
+/*
+	This manager tracks offsets of draggables and droppables
+*/
+$.ui.ddmanager = {
+	current: null,
+	droppables: { "default": [] },
+	prepareOffsets: function( t, event ) {
+
+		var i, j,
+			m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
+			type = event ? event.type : null, // workaround for #2317
+			list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
+
+		droppablesLoop: for ( i = 0; i < m.length; i++ ) {
+
+			// No disabled and non-accepted
+			if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) {
+				continue;
+			}
+
+			// Filter out elements in the current dragged item
+			for ( j = 0; j < list.length; j++ ) {
+				if ( list[ j ] === m[ i ].element[ 0 ] ) {
+					m[ i ].proportions().height = 0;
+					continue droppablesLoop;
+				}
+			}
+
+			m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
+			if ( !m[ i ].visible ) {
+				continue;
+			}
+
+			// Activate the droppable if used directly from draggables
+			if ( type === "mousedown" ) {
+				m[ i ]._activate.call( m[ i ], event );
+			}
+
+			m[ i ].offset = m[ i ].element.offset();
+			m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
+
+		}
+
+	},
+	drop: function( draggable, event ) {
+
+		var dropped = false;
+		// Create a copy of the droppables in case the list changes during the drop (#9116)
+		$.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
+
+			if ( !this.options ) {
+				return;
+			}
+			if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
+				dropped = this._drop.call( this, event ) || dropped;
+			}
+
+			if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
+				this.isout = true;
+				this.isover = false;
+				this._deactivate.call( this, event );
+			}
+
+		});
+		return dropped;
+
+	},
+	dragStart: function( draggable, event ) {
+		// Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
+		draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
+			if ( !draggable.options.refreshPositions ) {
+				$.ui.ddmanager.prepareOffsets( draggable, event );
+			}
+		});
+	},
+	drag: function( draggable, event ) {
+
+		// If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
+		if ( draggable.options.refreshPositions ) {
+			$.ui.ddmanager.prepareOffsets( draggable, event );
+		}
+
+		// Run through all droppables and check their positions based on specific tolerance options
+		$.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
+
+			if ( this.options.disabled || this.greedyChild || !this.visible ) {
+				return;
+			}
+
+			var parentInstance, scope, parent,
+				intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
+				c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null );
+			if ( !c ) {
+				return;
+			}
+
+			if ( this.options.greedy ) {
+				// find droppable parents with same scope
+				scope = this.options.scope;
+				parent = this.element.parents( ":data(ui-droppable)" ).filter(function() {
+					return $( this ).droppable( "instance" ).options.scope === scope;
+				});
+
+				if ( parent.length ) {
+					parentInstance = $( parent[ 0 ] ).droppable( "instance" );
+					parentInstance.greedyChild = ( c === "isover" );
+				}
+			}
+
+			// we just moved into a greedy child
+			if ( parentInstance && c === "isover" ) {
+				parentInstance.isover = false;
+				parentInstance.isout = true;
+				parentInstance._out.call( parentInstance, event );
+			}
+
+			this[ c ] = true;
+			this[c === "isout" ? "isover" : "isout"] = false;
+			this[c === "isover" ? "_over" : "_out"].call( this, event );
+
+			// we just moved out of a greedy child
+			if ( parentInstance && c === "isout" ) {
+				parentInstance.isout = false;
+				parentInstance.isover = true;
+				parentInstance._over.call( parentInstance, event );
+			}
+		});
+
+	},
+	dragStop: function( draggable, event ) {
+		draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
+		// Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
+		if ( !draggable.options.refreshPositions ) {
+			$.ui.ddmanager.prepareOffsets( draggable, event );
+		}
+	}
+};
+
+var droppable = $.ui.droppable;
+
+
+/*!
+ * jQuery UI Resizable 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/resizable/
+ */
+
+
+$.widget("ui.resizable", $.ui.mouse, {
+	version: "1.11.4",
+	widgetEventPrefix: "resize",
+	options: {
+		alsoResize: false,
+		animate: false,
+		animateDuration: "slow",
+		animateEasing: "swing",
+		aspectRatio: false,
+		autoHide: false,
+		containment: false,
+		ghost: false,
+		grid: false,
+		handles: "e,s,se",
+		helper: false,
+		maxHeight: null,
+		maxWidth: null,
+		minHeight: 10,
+		minWidth: 10,
+		// See #7960
+		zIndex: 90,
+
+		// callbacks
+		resize: null,
+		start: null,
+		stop: null
+	},
+
+	_num: function( value ) {
+		return parseInt( value, 10 ) || 0;
+	},
+
+	_isNumber: function( value ) {
+		return !isNaN( parseInt( value, 10 ) );
+	},
+
+	_hasScroll: function( el, a ) {
+
+		if ( $( el ).css( "overflow" ) === "hidden") {
+			return false;
+		}
+
+		var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
+			has = false;
+
+		if ( el[ scroll ] > 0 ) {
+			return true;
+		}
+
+		// TODO: determine which cases actually cause this to happen
+		// if the element doesn't have the scroll set, see if it's possible to
+		// set the scroll
+		el[ scroll ] = 1;
+		has = ( el[ scroll ] > 0 );
+		el[ scroll ] = 0;
+		return has;
+	},
+
+	_create: function() {
+
+		var n, i, handle, axis, hname,
+			that = this,
+			o = this.options;
+		this.element.addClass("ui-resizable");
+
+		$.extend(this, {
+			_aspectRatio: !!(o.aspectRatio),
+			aspectRatio: o.aspectRatio,
+			originalElement: this.element,
+			_proportionallyResizeElements: [],
+			_helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
+		});
+
+		// Wrap the element if it cannot hold child nodes
+		if (this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)) {
+
+			this.element.wrap(
+				$("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
+					position: this.element.css("position"),
+					width: this.element.outerWidth(),
+					height: this.element.outerHeight(),
+					top: this.element.css("top"),
+					left: this.element.css("left")
+				})
+			);
+
+			this.element = this.element.parent().data(
+				"ui-resizable", this.element.resizable( "instance" )
+			);
+
+			this.elementIsWrapper = true;
+
+			this.element.css({
+				marginLeft: this.originalElement.css("marginLeft"),
+				marginTop: this.originalElement.css("marginTop"),
+				marginRight: this.originalElement.css("marginRight"),
+				marginBottom: this.originalElement.css("marginBottom")
+			});
+			this.originalElement.css({
+				marginLeft: 0,
+				marginTop: 0,
+				marginRight: 0,
+				marginBottom: 0
+			});
+			// support: Safari
+			// Prevent Safari textarea resize
+			this.originalResizeStyle = this.originalElement.css("resize");
+			this.originalElement.css("resize", "none");
+
+			this._proportionallyResizeElements.push( this.originalElement.css({
+				position: "static",
+				zoom: 1,
+				display: "block"
+			}) );
+
+			// support: IE9
+			// avoid IE jump (hard set the margin)
+			this.originalElement.css({ margin: this.originalElement.css("margin") });
+
+			this._proportionallyResize();
+		}
+
+		this.handles = o.handles ||
+			( !$(".ui-resizable-handle", this.element).length ?
+				"e,s,se" : {
+					n: ".ui-resizable-n",
+					e: ".ui-resizable-e",
+					s: ".ui-resizable-s",
+					w: ".ui-resizable-w",
+					se: ".ui-resizable-se",
+					sw: ".ui-resizable-sw",
+					ne: ".ui-resizable-ne",
+					nw: ".ui-resizable-nw"
+				} );
+
+		this._handles = $();
+		if ( this.handles.constructor === String ) {
+
+			if ( this.handles === "all") {
+				this.handles = "n,e,s,w,se,sw,ne,nw";
+			}
+
+			n = this.handles.split(",");
+			this.handles = {};
+
+			for (i = 0; i < n.length; i++) {
+
+				handle = $.trim(n[i]);
+				hname = "ui-resizable-" + handle;
+				axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
+
+				axis.css({ zIndex: o.zIndex });
+
+				// TODO : What's going on here?
+				if ("se" === handle) {
+					axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
+				}
+
+				this.handles[handle] = ".ui-resizable-" + handle;
+				this.element.append(axis);
+			}
+
+		}
+
+		this._renderAxis = function(target) {
+
+			var i, axis, padPos, padWrapper;
+
+			target = target || this.element;
+
+			for (i in this.handles) {
+
+				if (this.handles[i].constructor === String) {
+					this.handles[i] = this.element.children( this.handles[ i ] ).first().show();
+				} else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
+					this.handles[ i ] = $( this.handles[ i ] );
+					this._on( this.handles[ i ], { "mousedown": that._mouseDown });
+				}
+
+				if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)) {
+
+					axis = $(this.handles[i], this.element);
+
+					padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
+
+					padPos = [ "padding",
+						/ne|nw|n/.test(i) ? "Top" :
+						/se|sw|s/.test(i) ? "Bottom" :
+						/^e$/.test(i) ? "Right" : "Left" ].join("");
+
+					target.css(padPos, padWrapper);
+
+					this._proportionallyResize();
+				}
+
+				this._handles = this._handles.add( this.handles[ i ] );
+			}
+		};
+
+		// TODO: make renderAxis a prototype function
+		this._renderAxis(this.element);
+
+		this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
+		this._handles.disableSelection();
+
+		this._handles.mouseover(function() {
+			if (!that.resizing) {
+				if (this.className) {
+					axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
+				}
+				that.axis = axis && axis[1] ? axis[1] : "se";
+			}
+		});
+
+		if (o.autoHide) {
+			this._handles.hide();
+			$(this.element)
+				.addClass("ui-resizable-autohide")
+				.mouseenter(function() {
+					if (o.disabled) {
+						return;
+					}
+					$(this).removeClass("ui-resizable-autohide");
+					that._handles.show();
+				})
+				.mouseleave(function() {
+					if (o.disabled) {
+						return;
+					}
+					if (!that.resizing) {
+						$(this).addClass("ui-resizable-autohide");
+						that._handles.hide();
+					}
+				});
+		}
+
+		this._mouseInit();
+	},
+
+	_destroy: function() {
+
+		this._mouseDestroy();
+
+		var wrapper,
+			_destroy = function(exp) {
+				$(exp)
+					.removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
+					.removeData("resizable")
+					.removeData("ui-resizable")
+					.unbind(".resizable")
+					.find(".ui-resizable-handle")
+						.remove();
+			};
+
+		// TODO: Unwrap at same DOM position
+		if (this.elementIsWrapper) {
+			_destroy(this.element);
+			wrapper = this.element;
+			this.originalElement.css({
+				position: wrapper.css("position"),
+				width: wrapper.outerWidth(),
+				height: wrapper.outerHeight(),
+				top: wrapper.css("top"),
+				left: wrapper.css("left")
+			}).insertAfter( wrapper );
+			wrapper.remove();
+		}
+
+		this.originalElement.css("resize", this.originalResizeStyle);
+		_destroy(this.originalElement);
+
+		return this;
+	},
+
+	_mouseCapture: function(event) {
+		var i, handle,
+			capture = false;
+
+		for (i in this.handles) {
+			handle = $(this.handles[i])[0];
+			if (handle === event.target || $.contains(handle, event.target)) {
+				capture = true;
+			}
+		}
+
+		return !this.options.disabled && capture;
+	},
+
+	_mouseStart: function(event) {
+
+		var curleft, curtop, cursor,
+			o = this.options,
+			el = this.element;
+
+		this.resizing = true;
+
+		this._renderProxy();
+
+		curleft = this._num(this.helper.css("left"));
+		curtop = this._num(this.helper.css("top"));
+
+		if (o.containment) {
+			curleft += $(o.containment).scrollLeft() || 0;
+			curtop += $(o.containment).scrollTop() || 0;
+		}
+
+		this.offset = this.helper.offset();
+		this.position = { left: curleft, top: curtop };
+
+		this.size = this._helper ? {
+				width: this.helper.width(),
+				height: this.helper.height()
+			} : {
+				width: el.width(),
+				height: el.height()
+			};
+
+		this.originalSize = this._helper ? {
+				width: el.outerWidth(),
+				height: el.outerHeight()
+			} : {
+				width: el.width(),
+				height: el.height()
+			};
+
+		this.sizeDiff = {
+			width: el.outerWidth() - el.width(),
+			height: el.outerHeight() - el.height()
+		};
+
+		this.originalPosition = { left: curleft, top: curtop };
+		this.originalMousePosition = { left: event.pageX, top: event.pageY };
+
+		this.aspectRatio = (typeof o.aspectRatio === "number") ?
+			o.aspectRatio :
+			((this.originalSize.width / this.originalSize.height) || 1);
+
+		cursor = $(".ui-resizable-" + this.axis).css("cursor");
+		$("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
+
+		el.addClass("ui-resizable-resizing");
+		this._propagate("start", event);
+		return true;
+	},
+
+	_mouseDrag: function(event) {
+
+		var data, props,
+			smp = this.originalMousePosition,
+			a = this.axis,
+			dx = (event.pageX - smp.left) || 0,
+			dy = (event.pageY - smp.top) || 0,
+			trigger = this._change[a];
+
+		this._updatePrevProperties();
+
+		if (!trigger) {
+			return false;
+		}
+
+		data = trigger.apply(this, [ event, dx, dy ]);
+
+		this._updateVirtualBoundaries(event.shiftKey);
+		if (this._aspectRatio || event.shiftKey) {
+			data = this._updateRatio(data, event);
+		}
+
+		data = this._respectSize(data, event);
+
+		this._updateCache(data);
+
+		this._propagate("resize", event);
+
+		props = this._applyChanges();
+
+		if ( !this._helper && this._proportionallyResizeElements.length ) {
+			this._proportionallyResize();
+		}
+
+		if ( !$.isEmptyObject( props ) ) {
+			this._updatePrevProperties();
+			this._trigger( "resize", event, this.ui() );
+			this._applyChanges();
+		}
+
+		return false;
+	},
+
+	_mouseStop: function(event) {
+
+		this.resizing = false;
+		var pr, ista, soffseth, soffsetw, s, left, top,
+			o = this.options, that = this;
+
+		if (this._helper) {
+
+			pr = this._proportionallyResizeElements;
+			ista = pr.length && (/textarea/i).test(pr[0].nodeName);
+			soffseth = ista && this._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height;
+			soffsetw = ista ? 0 : that.sizeDiff.width;
+
+			s = {
+				width: (that.helper.width()  - soffsetw),
+				height: (that.helper.height() - soffseth)
+			};
+			left = (parseInt(that.element.css("left"), 10) +
+				(that.position.left - that.originalPosition.left)) || null;
+			top = (parseInt(that.element.css("top"), 10) +
+				(that.position.top - that.originalPosition.top)) || null;
+
+			if (!o.animate) {
+				this.element.css($.extend(s, { top: top, left: left }));
+			}
+
+			that.helper.height(that.size.height);
+			that.helper.width(that.size.width);
+
+			if (this._helper && !o.animate) {
+				this._proportionallyResize();
+			}
+		}
+
+		$("body").css("cursor", "auto");
+
+		this.element.removeClass("ui-resizable-resizing");
+
+		this._propagate("stop", event);
+
+		if (this._helper) {
+			this.helper.remove();
+		}
+
+		return false;
+
+	},
+
+	_updatePrevProperties: function() {
+		this.prevPosition = {
+			top: this.position.top,
+			left: this.position.left
+		};
+		this.prevSize = {
+			width: this.size.width,
+			height: this.size.height
+		};
+	},
+
+	_applyChanges: function() {
+		var props = {};
+
+		if ( this.position.top !== this.prevPosition.top ) {
+			props.top = this.position.top + "px";
+		}
+		if ( this.position.left !== this.prevPosition.left ) {
+			props.left = this.position.left + "px";
+		}
+		if ( this.size.width !== this.prevSize.width ) {
+			props.width = this.size.width + "px";
+		}
+		if ( this.size.height !== this.prevSize.height ) {
+			props.height = this.size.height + "px";
+		}
+
+		this.helper.css( props );
+
+		return props;
+	},
+
+	_updateVirtualBoundaries: function(forceAspectRatio) {
+		var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
+			o = this.options;
+
+		b = {
+			minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0,
+			maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity,
+			minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0,
+			maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity
+		};
+
+		if (this._aspectRatio || forceAspectRatio) {
+			pMinWidth = b.minHeight * this.aspectRatio;
+			pMinHeight = b.minWidth / this.aspectRatio;
+			pMaxWidth = b.maxHeight * this.aspectRatio;
+			pMaxHeight = b.maxWidth / this.aspectRatio;
+
+			if (pMinWidth > b.minWidth) {
+				b.minWidth = pMinWidth;
+			}
+			if (pMinHeight > b.minHeight) {
+				b.minHeight = pMinHeight;
+			}
+			if (pMaxWidth < b.maxWidth) {
+				b.maxWidth = pMaxWidth;
+			}
+			if (pMaxHeight < b.maxHeight) {
+				b.maxHeight = pMaxHeight;
+			}
+		}
+		this._vBoundaries = b;
+	},
+
+	_updateCache: function(data) {
+		this.offset = this.helper.offset();
+		if (this._isNumber(data.left)) {
+			this.position.left = data.left;
+		}
+		if (this._isNumber(data.top)) {
+			this.position.top = data.top;
+		}
+		if (this._isNumber(data.height)) {
+			this.size.height = data.height;
+		}
+		if (this._isNumber(data.width)) {
+			this.size.width = data.width;
+		}
+	},
+
+	_updateRatio: function( data ) {
+
+		var cpos = this.position,
+			csize = this.size,
+			a = this.axis;
+
+		if (this._isNumber(data.height)) {
+			data.width = (data.height * this.aspectRatio);
+		} else if (this._isNumber(data.width)) {
+			data.height = (data.width / this.aspectRatio);
+		}
+
+		if (a === "sw") {
+			data.left = cpos.left + (csize.width - data.width);
+			data.top = null;
+		}
+		if (a === "nw") {
+			data.top = cpos.top + (csize.height - data.height);
+			data.left = cpos.left + (csize.width - data.width);
+		}
+
+		return data;
+	},
+
+	_respectSize: function( data ) {
+
+		var o = this._vBoundaries,
+			a = this.axis,
+			ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width),
+			ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
+			isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width),
+			isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
+			dw = this.originalPosition.left + this.originalSize.width,
+			dh = this.position.top + this.size.height,
+			cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
+		if (isminw) {
+			data.width = o.minWidth;
+		}
+		if (isminh) {
+			data.height = o.minHeight;
+		}
+		if (ismaxw) {
+			data.width = o.maxWidth;
+		}
+		if (ismaxh) {
+			data.height = o.maxHeight;
+		}
+
+		if (isminw && cw) {
+			data.left = dw - o.minWidth;
+		}
+		if (ismaxw && cw) {
+			data.left = dw - o.maxWidth;
+		}
+		if (isminh && ch) {
+			data.top = dh - o.minHeight;
+		}
+		if (ismaxh && ch) {
+			data.top = dh - o.maxHeight;
+		}
+
+		// Fixing jump error on top/left - bug #2330
+		if (!data.width && !data.height && !data.left && data.top) {
+			data.top = null;
+		} else if (!data.width && !data.height && !data.top && data.left) {
+			data.left = null;
+		}
+
+		return data;
+	},
+
+	_getPaddingPlusBorderDimensions: function( element ) {
+		var i = 0,
+			widths = [],
+			borders = [
+				element.css( "borderTopWidth" ),
+				element.css( "borderRightWidth" ),
+				element.css( "borderBottomWidth" ),
+				element.css( "borderLeftWidth" )
+			],
+			paddings = [
+				element.css( "paddingTop" ),
+				element.css( "paddingRight" ),
+				element.css( "paddingBottom" ),
+				element.css( "paddingLeft" )
+			];
+
+		for ( ; i < 4; i++ ) {
+			widths[ i ] = ( parseInt( borders[ i ], 10 ) || 0 );
+			widths[ i ] += ( parseInt( paddings[ i ], 10 ) || 0 );
+		}
+
+		return {
+			height: widths[ 0 ] + widths[ 2 ],
+			width: widths[ 1 ] + widths[ 3 ]
+		};
+	},
+
+	_proportionallyResize: function() {
+
+		if (!this._proportionallyResizeElements.length) {
+			return;
+		}
+
+		var prel,
+			i = 0,
+			element = this.helper || this.element;
+
+		for ( ; i < this._proportionallyResizeElements.length; i++) {
+
+			prel = this._proportionallyResizeElements[i];
+
+			// TODO: Seems like a bug to cache this.outerDimensions
+			// considering that we are in a loop.
+			if (!this.outerDimensions) {
+				this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
+			}
+
+			prel.css({
+				height: (element.height() - this.outerDimensions.height) || 0,
+				width: (element.width() - this.outerDimensions.width) || 0
+			});
+
+		}
+
+	},
+
+	_renderProxy: function() {
+
+		var el = this.element, o = this.options;
+		this.elementOffset = el.offset();
+
+		if (this._helper) {
+
+			this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
+
+			this.helper.addClass(this._helper).css({
+				width: this.element.outerWidth() - 1,
+				height: this.element.outerHeight() - 1,
+				position: "absolute",
+				left: this.elementOffset.left + "px",
+				top: this.elementOffset.top + "px",
+				zIndex: ++o.zIndex //TODO: Don't modify option
+			});
+
+			this.helper
+				.appendTo("body")
+				.disableSelection();
+
+		} else {
+			this.helper = this.element;
+		}
+
+	},
+
+	_change: {
+		e: function(event, dx) {
+			return { width: this.originalSize.width + dx };
+		},
+		w: function(event, dx) {
+			var cs = this.originalSize, sp = this.originalPosition;
+			return { left: sp.left + dx, width: cs.width - dx };
+		},
+		n: function(event, dx, dy) {
+			var cs = this.originalSize, sp = this.originalPosition;
+			return { top: sp.top + dy, height: cs.height - dy };
+		},
+		s: function(event, dx, dy) {
+			return { height: this.originalSize.height + dy };
+		},
+		se: function(event, dx, dy) {
+			return $.extend(this._change.s.apply(this, arguments),
+				this._change.e.apply(this, [ event, dx, dy ]));
+		},
+		sw: function(event, dx, dy) {
+			return $.extend(this._change.s.apply(this, arguments),
+				this._change.w.apply(this, [ event, dx, dy ]));
+		},
+		ne: function(event, dx, dy) {
+			return $.extend(this._change.n.apply(this, arguments),
+				this._change.e.apply(this, [ event, dx, dy ]));
+		},
+		nw: function(event, dx, dy) {
+			return $.extend(this._change.n.apply(this, arguments),
+				this._change.w.apply(this, [ event, dx, dy ]));
+		}
+	},
+
+	_propagate: function(n, event) {
+		$.ui.plugin.call(this, n, [ event, this.ui() ]);
+		(n !== "resize" && this._trigger(n, event, this.ui()));
+	},
+
+	plugins: {},
+
+	ui: function() {
+		return {
+			originalElement: this.originalElement,
+			element: this.element,
+			helper: this.helper,
+			position: this.position,
+			size: this.size,
+			originalSize: this.originalSize,
+			originalPosition: this.originalPosition
+		};
+	}
+
+});
+
+/*
+ * Resizable Extensions
+ */
+
+$.ui.plugin.add("resizable", "animate", {
+
+	stop: function( event ) {
+		var that = $(this).resizable( "instance" ),
+			o = that.options,
+			pr = that._proportionallyResizeElements,
+			ista = pr.length && (/textarea/i).test(pr[0].nodeName),
+			soffseth = ista && that._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height,
+			soffsetw = ista ? 0 : that.sizeDiff.width,
+			style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
+			left = (parseInt(that.element.css("left"), 10) +
+				(that.position.left - that.originalPosition.left)) || null,
+			top = (parseInt(that.element.css("top"), 10) +
+				(that.position.top - that.originalPosition.top)) || null;
+
+		that.element.animate(
+			$.extend(style, top && left ? { top: top, left: left } : {}), {
+				duration: o.animateDuration,
+				easing: o.animateEasing,
+				step: function() {
+
+					var data = {
+						width: parseInt(that.element.css("width"), 10),
+						height: parseInt(that.element.css("height"), 10),
+						top: parseInt(that.element.css("top"), 10),
+						left: parseInt(that.element.css("left"), 10)
+					};
+
+					if (pr && pr.length) {
+						$(pr[0]).css({ width: data.width, height: data.height });
+					}
+
+					// propagating resize, and updating values for each animation step
+					that._updateCache(data);
+					that._propagate("resize", event);
+
+				}
+			}
+		);
+	}
+
+});
+
+$.ui.plugin.add( "resizable", "containment", {
+
+	start: function() {
+		var element, p, co, ch, cw, width, height,
+			that = $( this ).resizable( "instance" ),
+			o = that.options,
+			el = that.element,
+			oc = o.containment,
+			ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
+
+		if ( !ce ) {
+			return;
+		}
+
+		that.containerElement = $( ce );
+
+		if ( /document/.test( oc ) || oc === document ) {
+			that.containerOffset = {
+				left: 0,
+				top: 0
+			};
+			that.containerPosition = {
+				left: 0,
+				top: 0
+			};
+
+			that.parentData = {
+				element: $( document ),
+				left: 0,
+				top: 0,
+				width: $( document ).width(),
+				height: $( document ).height() || document.body.parentNode.scrollHeight
+			};
+		} else {
+			element = $( ce );
+			p = [];
+			$([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) {
+				p[ i ] = that._num( element.css( "padding" + name ) );
+			});
+
+			that.containerOffset = element.offset();
+			that.containerPosition = element.position();
+			that.containerSize = {
+				height: ( element.innerHeight() - p[ 3 ] ),
+				width: ( element.innerWidth() - p[ 1 ] )
+			};
+
+			co = that.containerOffset;
+			ch = that.containerSize.height;
+			cw = that.containerSize.width;
+			width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
+			height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
+
+			that.parentData = {
+				element: ce,
+				left: co.left,
+				top: co.top,
+				width: width,
+				height: height
+			};
+		}
+	},
+
+	resize: function( event ) {
+		var woset, hoset, isParent, isOffsetRelative,
+			that = $( this ).resizable( "instance" ),
+			o = that.options,
+			co = that.containerOffset,
+			cp = that.position,
+			pRatio = that._aspectRatio || event.shiftKey,
+			cop = {
+				top: 0,
+				left: 0
+			},
+			ce = that.containerElement,
+			continueResize = true;
+
+		if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
+			cop = co;
+		}
+
+		if ( cp.left < ( that._helper ? co.left : 0 ) ) {
+			that.size.width = that.size.width +
+				( that._helper ?
+					( that.position.left - co.left ) :
+					( that.position.left - cop.left ) );
+
+			if ( pRatio ) {
+				that.size.height = that.size.width / that.aspectRatio;
+				continueResize = false;
+			}
+			that.position.left = o.helper ? co.left : 0;
+		}
+
+		if ( cp.top < ( that._helper ? co.top : 0 ) ) {
+			that.size.height = that.size.height +
+				( that._helper ?
+					( that.position.top - co.top ) :
+					that.position.top );
+
+			if ( pRatio ) {
+				that.size.width = that.size.height * that.aspectRatio;
+				continueResize = false;
+			}
+			that.position.top = that._helper ? co.top : 0;
+		}
+
+		isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
+		isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
+
+		if ( isParent && isOffsetRelative ) {
+			that.offset.left = that.parentData.left + that.position.left;
+			that.offset.top = that.parentData.top + that.position.top;
+		} else {
+			that.offset.left = that.element.offset().left;
+			that.offset.top = that.element.offset().top;
+		}
+
+		woset = Math.abs( that.sizeDiff.width +
+			(that._helper ?
+				that.offset.left - cop.left :
+				(that.offset.left - co.left)) );
+
+		hoset = Math.abs( that.sizeDiff.height +
+			(that._helper ?
+				that.offset.top - cop.top :
+				(that.offset.top - co.top)) );
+
+		if ( woset + that.size.width >= that.parentData.width ) {
+			that.size.width = that.parentData.width - woset;
+			if ( pRatio ) {
+				that.size.height = that.size.width / that.aspectRatio;
+				continueResize = false;
+			}
+		}
+
+		if ( hoset + that.size.height >= that.parentData.height ) {
+			that.size.height = that.parentData.height - hoset;
+			if ( pRatio ) {
+				that.size.width = that.size.height * that.aspectRatio;
+				continueResize = false;
+			}
+		}
+
+		if ( !continueResize ) {
+			that.position.left = that.prevPosition.left;
+			that.position.top = that.prevPosition.top;
+			that.size.width = that.prevSize.width;
+			that.size.height = that.prevSize.height;
+		}
+	},
+
+	stop: function() {
+		var that = $( this ).resizable( "instance" ),
+			o = that.options,
+			co = that.containerOffset,
+			cop = that.containerPosition,
+			ce = that.containerElement,
+			helper = $( that.helper ),
+			ho = helper.offset(),
+			w = helper.outerWidth() - that.sizeDiff.width,
+			h = helper.outerHeight() - that.sizeDiff.height;
+
+		if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
+			$( this ).css({
+				left: ho.left - cop.left - co.left,
+				width: w,
+				height: h
+			});
+		}
+
+		if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
+			$( this ).css({
+				left: ho.left - cop.left - co.left,
+				width: w,
+				height: h
+			});
+		}
+	}
+});
+
+$.ui.plugin.add("resizable", "alsoResize", {
+
+	start: function() {
+		var that = $(this).resizable( "instance" ),
+			o = that.options;
+
+		$(o.alsoResize).each(function() {
+			var el = $(this);
+			el.data("ui-resizable-alsoresize", {
+				width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
+				left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
+			});
+		});
+	},
+
+	resize: function(event, ui) {
+		var that = $(this).resizable( "instance" ),
+			o = that.options,
+			os = that.originalSize,
+			op = that.originalPosition,
+			delta = {
+				height: (that.size.height - os.height) || 0,
+				width: (that.size.width - os.width) || 0,
+				top: (that.position.top - op.top) || 0,
+				left: (that.position.left - op.left) || 0
+			};
+
+			$(o.alsoResize).each(function() {
+				var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
+					css = el.parents(ui.originalElement[0]).length ?
+							[ "width", "height" ] :
+							[ "width", "height", "top", "left" ];
+
+				$.each(css, function(i, prop) {
+					var sum = (start[prop] || 0) + (delta[prop] || 0);
+					if (sum && sum >= 0) {
+						style[prop] = sum || null;
+					}
+				});
+
+				el.css(style);
+			});
+	},
+
+	stop: function() {
+		$(this).removeData("resizable-alsoresize");
+	}
+});
+
+$.ui.plugin.add("resizable", "ghost", {
+
+	start: function() {
+
+		var that = $(this).resizable( "instance" ), o = that.options, cs = that.size;
+
+		that.ghost = that.originalElement.clone();
+		that.ghost
+			.css({
+				opacity: 0.25,
+				display: "block",
+				position: "relative",
+				height: cs.height,
+				width: cs.width,
+				margin: 0,
+				left: 0,
+				top: 0
+			})
+			.addClass("ui-resizable-ghost")
+			.addClass(typeof o.ghost === "string" ? o.ghost : "");
+
+		that.ghost.appendTo(that.helper);
+
+	},
+
+	resize: function() {
+		var that = $(this).resizable( "instance" );
+		if (that.ghost) {
+			that.ghost.css({
+				position: "relative",
+				height: that.size.height,
+				width: that.size.width
+			});
+		}
+	},
+
+	stop: function() {
+		var that = $(this).resizable( "instance" );
+		if (that.ghost && that.helper) {
+			that.helper.get(0).removeChild(that.ghost.get(0));
+		}
+	}
+
+});
+
+$.ui.plugin.add("resizable", "grid", {
+
+	resize: function() {
+		var outerDimensions,
+			that = $(this).resizable( "instance" ),
+			o = that.options,
+			cs = that.size,
+			os = that.originalSize,
+			op = that.originalPosition,
+			a = that.axis,
+			grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
+			gridX = (grid[0] || 1),
+			gridY = (grid[1] || 1),
+			ox = Math.round((cs.width - os.width) / gridX) * gridX,
+			oy = Math.round((cs.height - os.height) / gridY) * gridY,
+			newWidth = os.width + ox,
+			newHeight = os.height + oy,
+			isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
+			isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
+			isMinWidth = o.minWidth && (o.minWidth > newWidth),
+			isMinHeight = o.minHeight && (o.minHeight > newHeight);
+
+		o.grid = grid;
+
+		if (isMinWidth) {
+			newWidth += gridX;
+		}
+		if (isMinHeight) {
+			newHeight += gridY;
+		}
+		if (isMaxWidth) {
+			newWidth -= gridX;
+		}
+		if (isMaxHeight) {
+			newHeight -= gridY;
+		}
+
+		if (/^(se|s|e)$/.test(a)) {
+			that.size.width = newWidth;
+			that.size.height = newHeight;
+		} else if (/^(ne)$/.test(a)) {
+			that.size.width = newWidth;
+			that.size.height = newHeight;
+			that.position.top = op.top - oy;
+		} else if (/^(sw)$/.test(a)) {
+			that.size.width = newWidth;
+			that.size.height = newHeight;
+			that.position.left = op.left - ox;
+		} else {
+			if ( newHeight - gridY <= 0 || newWidth - gridX <= 0) {
+				outerDimensions = that._getPaddingPlusBorderDimensions( this );
+			}
+
+			if ( newHeight - gridY > 0 ) {
+				that.size.height = newHeight;
+				that.position.top = op.top - oy;
+			} else {
+				newHeight = gridY - outerDimensions.height;
+				that.size.height = newHeight;
+				that.position.top = op.top + os.height - newHeight;
+			}
+			if ( newWidth - gridX > 0 ) {
+				that.size.width = newWidth;
+				that.position.left = op.left - ox;
+			} else {
+				newWidth = gridX - outerDimensions.width;
+				that.size.width = newWidth;
+				that.position.left = op.left + os.width - newWidth;
+			}
+		}
+	}
+
+});
+
+var resizable = $.ui.resizable;
+
+
+/*!
+ * jQuery UI Selectable 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/selectable/
+ */
+
+
+var selectable = $.widget("ui.selectable", $.ui.mouse, {
+	version: "1.11.4",
+	options: {
+		appendTo: "body",
+		autoRefresh: true,
+		distance: 0,
+		filter: "*",
+		tolerance: "touch",
+
+		// callbacks
+		selected: null,
+		selecting: null,
+		start: null,
+		stop: null,
+		unselected: null,
+		unselecting: null
+	},
+	_create: function() {
+		var selectees,
+			that = this;
+
+		this.element.addClass("ui-selectable");
+
+		this.dragged = false;
+
+		// cache selectee children based on filter
+		this.refresh = function() {
+			selectees = $(that.options.filter, that.element[0]);
+			selectees.addClass("ui-selectee");
+			selectees.each(function() {
+				var $this = $(this),
+					pos = $this.offset();
+				$.data(this, "selectable-item", {
+					element: this,
+					$element: $this,
+					left: pos.left,
+					top: pos.top,
+					right: pos.left + $this.outerWidth(),
+					bottom: pos.top + $this.outerHeight(),
+					startselected: false,
+					selected: $this.hasClass("ui-selected"),
+					selecting: $this.hasClass("ui-selecting"),
+					unselecting: $this.hasClass("ui-unselecting")
+				});
+			});
+		};
+		this.refresh();
+
+		this.selectees = selectees.addClass("ui-selectee");
+
+		this._mouseInit();
+
+		this.helper = $("<div class='ui-selectable-helper'></div>");
+	},
+
+	_destroy: function() {
+		this.selectees
+			.removeClass("ui-selectee")
+			.removeData("selectable-item");
+		this.element
+			.removeClass("ui-selectable ui-selectable-disabled");
+		this._mouseDestroy();
+	},
+
+	_mouseStart: function(event) {
+		var that = this,
+			options = this.options;
+
+		this.opos = [ event.pageX, event.pageY ];
+
+		if (this.options.disabled) {
+			return;
+		}
+
+		this.selectees = $(options.filter, this.element[0]);
+
+		this._trigger("start", event);
+
+		$(options.appendTo).append(this.helper);
+		// position helper (lasso)
+		this.helper.css({
+			"left": event.pageX,
+			"top": event.pageY,
+			"width": 0,
+			"height": 0
+		});
+
+		if (options.autoRefresh) {
+			this.refresh();
+		}
+
+		this.selectees.filter(".ui-selected").each(function() {
+			var selectee = $.data(this, "selectable-item");
+			selectee.startselected = true;
+			if (!event.metaKey && !event.ctrlKey) {
+				selectee.$element.removeClass("ui-selected");
+				selectee.selected = false;
+				selectee.$element.addClass("ui-unselecting");
+				selectee.unselecting = true;
+				// selectable UNSELECTING callback
+				that._trigger("unselecting", event, {
+					unselecting: selectee.element
+				});
+			}
+		});
+
+		$(event.target).parents().addBack().each(function() {
+			var doSelect,
+				selectee = $.data(this, "selectable-item");
+			if (selectee) {
+				doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
+				selectee.$element
+					.removeClass(doSelect ? "ui-unselecting" : "ui-selected")
+					.addClass(doSelect ? "ui-selecting" : "ui-unselecting");
+				selectee.unselecting = !doSelect;
+				selectee.selecting = doSelect;
+				selectee.selected = doSelect;
+				// selectable (UN)SELECTING callback
+				if (doSelect) {
+					that._trigger("selecting", event, {
+						selecting: selectee.element
+					});
+				} else {
+					that._trigger("unselecting", event, {
+						unselecting: selectee.element
+					});
+				}
+				return false;
+			}
+		});
+
+	},
+
+	_mouseDrag: function(event) {
+
+		this.dragged = true;
+
+		if (this.options.disabled) {
+			return;
+		}
+
+		var tmp,
+			that = this,
+			options = this.options,
+			x1 = this.opos[0],
+			y1 = this.opos[1],
+			x2 = event.pageX,
+			y2 = event.pageY;
+
+		if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
+		if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
+		this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 });
+
+		this.selectees.each(function() {
+			var selectee = $.data(this, "selectable-item"),
+				hit = false;
+
+			//prevent helper from being selected if appendTo: selectable
+			if (!selectee || selectee.element === that.element[0]) {
+				return;
+			}
+
+			if (options.tolerance === "touch") {
+				hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
+			} else if (options.tolerance === "fit") {
+				hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
+			}
+
+			if (hit) {
+				// SELECT
+				if (selectee.selected) {
+					selectee.$element.removeClass("ui-selected");
+					selectee.selected = false;
+				}
+				if (selectee.unselecting) {
+					selectee.$element.removeClass("ui-unselecting");
+					selectee.unselecting = false;
+				}
+				if (!selectee.selecting) {
+					selectee.$element.addClass("ui-selecting");
+					selectee.selecting = true;
+					// selectable SELECTING callback
+					that._trigger("selecting", event, {
+						selecting: selectee.element
+					});
+				}
+			} else {
+				// UNSELECT
+				if (selectee.selecting) {
+					if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
+						selectee.$element.removeClass("ui-selecting");
+						selectee.selecting = false;
+						selectee.$element.addClass("ui-selected");
+						selectee.selected = true;
+					} else {
+						selectee.$element.removeClass("ui-selecting");
+						selectee.selecting = false;
+						if (selectee.startselected) {
+							selectee.$element.addClass("ui-unselecting");
+							selectee.unselecting = true;
+						}
+						// selectable UNSELECTING callback
+						that._trigger("unselecting", event, {
+							unselecting: selectee.element
+						});
+					}
+				}
+				if (selectee.selected) {
+					if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
+						selectee.$element.removeClass("ui-selected");
+						selectee.selected = false;
+
+						selectee.$element.addClass("ui-unselecting");
+						selectee.unselecting = true;
+						// selectable UNSELECTING callback
+						that._trigger("unselecting", event, {
+							unselecting: selectee.element
+						});
+					}
+				}
+			}
+		});
+
+		return false;
+	},
+
+	_mouseStop: function(event) {
+		var that = this;
+
+		this.dragged = false;
+
+		$(".ui-unselecting", this.element[0]).each(function() {
+			var selectee = $.data(this, "selectable-item");
+			selectee.$element.removeClass("ui-unselecting");
+			selectee.unselecting = false;
+			selectee.startselected = false;
+			that._trigger("unselected", event, {
+				unselected: selectee.element
+			});
+		});
+		$(".ui-selecting", this.element[0]).each(function() {
+			var selectee = $.data(this, "selectable-item");
+			selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
+			selectee.selecting = false;
+			selectee.selected = true;
+			selectee.startselected = true;
+			that._trigger("selected", event, {
+				selected: selectee.element
+			});
+		});
+		this._trigger("stop", event);
+
+		this.helper.remove();
+
+		return false;
+	}
+
+});
+
+
+/*!
+ * jQuery UI Sortable 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/sortable/
+ */
+
+
+var sortable = $.widget("ui.sortable", $.ui.mouse, {
+	version: "1.11.4",
+	widgetEventPrefix: "sort",
+	ready: false,
+	options: {
+		appendTo: "parent",
+		axis: false,
+		connectWith: false,
+		containment: false,
+		cursor: "auto",
+		cursorAt: false,
+		dropOnEmpty: true,
+		forcePlaceholderSize: false,
+		forceHelperSize: false,
+		grid: false,
+		handle: false,
+		helper: "original",
+		items: "> *",
+		opacity: false,
+		placeholder: false,
+		revert: false,
+		scroll: true,
+		scrollSensitivity: 20,
+		scrollSpeed: 20,
+		scope: "default",
+		tolerance: "intersect",
+		zIndex: 1000,
+
+		// callbacks
+		activate: null,
+		beforeStop: null,
+		change: null,
+		deactivate: null,
+		out: null,
+		over: null,
+		receive: null,
+		remove: null,
+		sort: null,
+		start: null,
+		stop: null,
+		update: null
+	},
+
+	_isOverAxis: function( x, reference, size ) {
+		return ( x >= reference ) && ( x < ( reference + size ) );
+	},
+
+	_isFloating: function( item ) {
+		return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
+	},
+
+	_create: function() {
+		this.containerCache = {};
+		this.element.addClass("ui-sortable");
+
+		//Get the items
+		this.refresh();
+
+		//Let's determine the parent's offset
+		this.offset = this.element.offset();
+
+		//Initialize mouse events for interaction
+		this._mouseInit();
+
+		this._setHandleClassName();
+
+		//We're ready to go
+		this.ready = true;
+
+	},
+
+	_setOption: function( key, value ) {
+		this._super( key, value );
+
+		if ( key === "handle" ) {
+			this._setHandleClassName();
+		}
+	},
+
+	_setHandleClassName: function() {
+		this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" );
+		$.each( this.items, function() {
+			( this.instance.options.handle ?
+				this.item.find( this.instance.options.handle ) : this.item )
+				.addClass( "ui-sortable-handle" );
+		});
+	},
+
+	_destroy: function() {
+		this.element
+			.removeClass( "ui-sortable ui-sortable-disabled" )
+			.find( ".ui-sortable-handle" )
+				.removeClass( "ui-sortable-handle" );
+		this._mouseDestroy();
+
+		for ( var i = this.items.length - 1; i >= 0; i-- ) {
+			this.items[i].item.removeData(this.widgetName + "-item");
+		}
+
+		return this;
+	},
+
+	_mouseCapture: function(event, overrideHandle) {
+		var currentItem = null,
+			validHandle = false,
+			that = this;
+
+		if (this.reverting) {
+			return false;
+		}
+
+		if(this.options.disabled || this.options.type === "static") {
+			return false;
+		}
+
+		//We have to refresh the items data once first
+		this._refreshItems(event);
+
+		//Find out if the clicked node (or one of its parents) is a actual item in this.items
+		$(event.target).parents().each(function() {
+			if($.data(this, that.widgetName + "-item") === that) {
+				currentItem = $(this);
+				return false;
+			}
+		});
+		if($.data(event.target, that.widgetName + "-item") === that) {
+			currentItem = $(event.target);
+		}
+
+		if(!currentItem) {
+			return false;
+		}
+		if(this.options.handle && !overrideHandle) {
+			$(this.options.handle, currentItem).find("*").addBack().each(function() {
+				if(this === event.target) {
+					validHandle = true;
+				}
+			});
+			if(!validHandle) {
+				return false;
+			}
+		}
+
+		this.currentItem = currentItem;
+		this._removeCurrentsFromItems();
+		return true;
+
+	},
+
+	_mouseStart: function(event, overrideHandle, noActivation) {
+
+		var i, body,
+			o = this.options;
+
+		this.currentContainer = this;
+
+		//We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
+		this.refreshPositions();
+
+		//Create and append the visible helper
+		this.helper = this._createHelper(event);
+
+		//Cache the helper size
+		this._cacheHelperProportions();
+
+		/*
+		 * - Position generation -
+		 * This block generates everything position related - it's the core of draggables.
+		 */
+
+		//Cache the margins of the original element
+		this._cacheMargins();
+
+		//Get the next scrolling parent
+		this.scrollParent = this.helper.scrollParent();
+
+		//The element's absolute position on the page minus margins
+		this.offset = this.currentItem.offset();
+		this.offset = {
+			top: this.offset.top - this.margins.top,
+			left: this.offset.left - this.margins.left
+		};
+
+		$.extend(this.offset, {
+			click: { //Where the click happened, relative to the element
+				left: event.pageX - this.offset.left,
+				top: event.pageY - this.offset.top
+			},
+			parent: this._getParentOffset(),
+			relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+		});
+
+		// Only after we got the offset, we can change the helper's position to absolute
+		// TODO: Still need to figure out a way to make relative sorting possible
+		this.helper.css("position", "absolute");
+		this.cssPosition = this.helper.css("position");
+
+		//Generate the original position
+		this.originalPosition = this._generatePosition(event);
+		this.originalPageX = event.pageX;
+		this.originalPageY = event.pageY;
+
+		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+		(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+		//Cache the former DOM position
+		this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
+
+		//If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
+		if(this.helper[0] !== this.currentItem[0]) {
+			this.currentItem.hide();
+		}
+
+		//Create the placeholder
+		this._createPlaceholder();
+
+		//Set a containment if given in the options
+		if(o.containment) {
+			this._setContainment();
+		}
+
+		if( o.cursor && o.cursor !== "auto" ) { // cursor option
+			body = this.document.find( "body" );
+
+			// support: IE
+			this.storedCursor = body.css( "cursor" );
+			body.css( "cursor", o.cursor );
+
+			this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
+		}
+
+		if(o.opacity) { // opacity option
+			if (this.helper.css("opacity")) {
+				this._storedOpacity = this.helper.css("opacity");
+			}
+			this.helper.css("opacity", o.opacity);
+		}
+
+		if(o.zIndex) { // zIndex option
+			if (this.helper.css("zIndex")) {
+				this._storedZIndex = this.helper.css("zIndex");
+			}
+			this.helper.css("zIndex", o.zIndex);
+		}
+
+		//Prepare scrolling
+		if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
+			this.overflowOffset = this.scrollParent.offset();
+		}
+
+		//Call callbacks
+		this._trigger("start", event, this._uiHash());
+
+		//Recache the helper size
+		if(!this._preserveHelperProportions) {
+			this._cacheHelperProportions();
+		}
+
+
+		//Post "activate" events to possible containers
+		if( !noActivation ) {
+			for ( i = this.containers.length - 1; i >= 0; i-- ) {
+				this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
+			}
+		}
+
+		//Prepare possible droppables
+		if($.ui.ddmanager) {
+			$.ui.ddmanager.current = this;
+		}
+
+		if ($.ui.ddmanager && !o.dropBehaviour) {
+			$.ui.ddmanager.prepareOffsets(this, event);
+		}
+
+		this.dragging = true;
+
+		this.helper.addClass("ui-sortable-helper");
+		this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+		return true;
+
+	},
+
+	_mouseDrag: function(event) {
+		var i, item, itemElement, intersection,
+			o = this.options,
+			scrolled = false;
+
+		//Compute the helpers position
+		this.position = this._generatePosition(event);
+		this.positionAbs = this._convertPositionTo("absolute");
+
+		if (!this.lastPositionAbs) {
+			this.lastPositionAbs = this.positionAbs;
+		}
+
+		//Do scrolling
+		if(this.options.scroll) {
+			if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
+
+				if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
+					this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
+				} else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
+					this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
+				}
+
+				if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
+					this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
+				} else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
+					this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
+				}
+
+			} else {
+
+				if(event.pageY - this.document.scrollTop() < o.scrollSensitivity) {
+					scrolled = this.document.scrollTop(this.document.scrollTop() - o.scrollSpeed);
+				} else if(this.window.height() - (event.pageY - this.document.scrollTop()) < o.scrollSensitivity) {
+					scrolled = this.document.scrollTop(this.document.scrollTop() + o.scrollSpeed);
+				}
+
+				if(event.pageX - this.document.scrollLeft() < o.scrollSensitivity) {
+					scrolled = this.document.scrollLeft(this.document.scrollLeft() - o.scrollSpeed);
+				} else if(this.window.width() - (event.pageX - this.document.scrollLeft()) < o.scrollSensitivity) {
+					scrolled = this.document.scrollLeft(this.document.scrollLeft() + o.scrollSpeed);
+				}
+
+			}
+
+			if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+				$.ui.ddmanager.prepareOffsets(this, event);
+			}
+		}
+
+		//Regenerate the absolute position used for position checks
+		this.positionAbs = this._convertPositionTo("absolute");
+
+		//Set the helper position
+		if(!this.options.axis || this.options.axis !== "y") {
+			this.helper[0].style.left = this.position.left+"px";
+		}
+		if(!this.options.axis || this.options.axis !== "x") {
+			this.helper[0].style.top = this.position.top+"px";
+		}
+
+		//Rearrange
+		for (i = this.items.length - 1; i >= 0; i--) {
+
+			//Cache variables and intersection, continue if no intersection
+			item = this.items[i];
+			itemElement = item.item[0];
+			intersection = this._intersectsWithPointer(item);
+			if (!intersection) {
+				continue;
+			}
+
+			// Only put the placeholder inside the current Container, skip all
+			// items from other containers. This works because when moving
+			// an item from one container to another the
+			// currentContainer is switched before the placeholder is moved.
+			//
+			// Without this, moving items in "sub-sortables" can cause
+			// the placeholder to jitter between the outer and inner container.
+			if (item.instance !== this.currentContainer) {
+				continue;
+			}
+
+			// cannot intersect with itself
+			// no useless actions that have been done before
+			// no action if the item moved is the parent of the item checked
+			if (itemElement !== this.currentItem[0] &&
+				this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
+				!$.contains(this.placeholder[0], itemElement) &&
+				(this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
+			) {
+
+				this.direction = intersection === 1 ? "down" : "up";
+
+				if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
+					this._rearrange(event, item);
+				} else {
+					break;
+				}
+
+				this._trigger("change", event, this._uiHash());
+				break;
+			}
+		}
+
+		//Post events to containers
+		this._contactContainers(event);
+
+		//Interconnect with droppables
+		if($.ui.ddmanager) {
+			$.ui.ddmanager.drag(this, event);
+		}
+
+		//Call callbacks
+		this._trigger("sort", event, this._uiHash());
+
+		this.lastPositionAbs = this.positionAbs;
+		return false;
+
+	},
+
+	_mouseStop: function(event, noPropagation) {
+
+		if(!event) {
+			return;
+		}
+
+		//If we are using droppables, inform the manager about the drop
+		if ($.ui.ddmanager && !this.options.dropBehaviour) {
+			$.ui.ddmanager.drop(this, event);
+		}
+
+		if(this.options.revert) {
+			var that = this,
+				cur = this.placeholder.offset(),
+				axis = this.options.axis,
+				animation = {};
+
+			if ( !axis || axis === "x" ) {
+				animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollLeft);
+			}
+			if ( !axis || axis === "y" ) {
+				animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollTop);
+			}
+			this.reverting = true;
+			$(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
+				that._clear(event);
+			});
+		} else {
+			this._clear(event, noPropagation);
+		}
+
+		return false;
+
+	},
+
+	cancel: function() {
+
+		if(this.dragging) {
+
+			this._mouseUp({ target: null });
+
+			if(this.options.helper === "original") {
+				this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+			} else {
+				this.currentItem.show();
+			}
+
+			//Post deactivating events to containers
+			for (var i = this.containers.length - 1; i >= 0; i--){
+				this.containers[i]._trigger("deactivate", null, this._uiHash(this));
+				if(this.containers[i].containerCache.over) {
+					this.containers[i]._trigger("out", null, this._uiHash(this));
+					this.containers[i].containerCache.over = 0;
+				}
+			}
+
+		}
+
+		if (this.placeholder) {
+			//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+			if(this.placeholder[0].parentNode) {
+				this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+			}
+			if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
+				this.helper.remove();
+			}
+
+			$.extend(this, {
+				helper: null,
+				dragging: false,
+				reverting: false,
+				_noFinalSort: null
+			});
+
+			if(this.domPosition.prev) {
+				$(this.domPosition.prev).after(this.currentItem);
+			} else {
+				$(this.domPosition.parent).prepend(this.currentItem);
+			}
+		}
+
+		return this;
+
+	},
+
+	serialize: function(o) {
+
+		var items = this._getItemsAsjQuery(o && o.connected),
+			str = [];
+		o = o || {};
+
+		$(items).each(function() {
+			var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
+			if (res) {
+				str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
+			}
+		});
+
+		if(!str.length && o.key) {
+			str.push(o.key + "=");
+		}
+
+		return str.join("&");
+
+	},
+
+	toArray: function(o) {
+
+		var items = this._getItemsAsjQuery(o && o.connected),
+			ret = [];
+
+		o = o || {};
+
+		items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
+		return ret;
+
+	},
+
+	/* Be careful with the following core functions */
+	_intersectsWith: function(item) {
+
+		var x1 = this.positionAbs.left,
+			x2 = x1 + this.helperProportions.width,
+			y1 = this.positionAbs.top,
+			y2 = y1 + this.helperProportions.height,
+			l = item.left,
+			r = l + item.width,
+			t = item.top,
+			b = t + item.height,
+			dyClick = this.offset.click.top,
+			dxClick = this.offset.click.left,
+			isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
+			isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
+			isOverElement = isOverElementHeight && isOverElementWidth;
+
+		if ( this.options.tolerance === "pointer" ||
+			this.options.forcePointerForContainers ||
+			(this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
+		) {
+			return isOverElement;
+		} else {
+
+			return (l < x1 + (this.helperProportions.width / 2) && // Right Half
+				x2 - (this.helperProportions.width / 2) < r && // Left Half
+				t < y1 + (this.helperProportions.height / 2) && // Bottom Half
+				y2 - (this.helperProportions.height / 2) < b ); // Top Half
+
+		}
+	},
+
+	_intersectsWithPointer: function(item) {
+
+		var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
+			isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
+			isOverElement = isOverElementHeight && isOverElementWidth,
+			verticalDirection = this._getDragVerticalDirection(),
+			horizontalDirection = this._getDragHorizontalDirection();
+
+		if (!isOverElement) {
+			return false;
+		}
+
+		return this.floating ?
+			( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
+			: ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
+
+	},
+
+	_intersectsWithSides: function(item) {
+
+		var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
+			isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
+			verticalDirection = this._getDragVerticalDirection(),
+			horizontalDirection = this._getDragHorizontalDirection();
+
+		if (this.floating && horizontalDirection) {
+			return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
+		} else {
+			return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
+		}
+
+	},
+
+	_getDragVerticalDirection: function() {
+		var delta = this.positionAbs.top - this.lastPositionAbs.top;
+		return delta !== 0 && (delta > 0 ? "down" : "up");
+	},
+
+	_getDragHorizontalDirection: function() {
+		var delta = this.positionAbs.left - this.lastPositionAbs.left;
+		return delta !== 0 && (delta > 0 ? "right" : "left");
+	},
+
+	refresh: function(event) {
+		this._refreshItems(event);
+		this._setHandleClassName();
+		this.refreshPositions();
+		return this;
+	},
+
+	_connectWith: function() {
+		var options = this.options;
+		return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
+	},
+
+	_getItemsAsjQuery: function(connected) {
+
+		var i, j, cur, inst,
+			items = [],
+			queries = [],
+			connectWith = this._connectWith();
+
+		if(connectWith && connected) {
+			for (i = connectWith.length - 1; i >= 0; i--){
+				cur = $(connectWith[i], this.document[0]);
+				for ( j = cur.length - 1; j >= 0; j--){
+					inst = $.data(cur[j], this.widgetFullName);
+					if(inst && inst !== this && !inst.options.disabled) {
+						queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]);
+					}
+				}
+			}
+		}
+
+		queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]);
+
+		function addItems() {
+			items.push( this );
+		}
+		for (i = queries.length - 1; i >= 0; i--){
+			queries[i][0].each( addItems );
+		}
+
+		return $(items);
+
+	},
+
+	_removeCurrentsFromItems: function() {
+
+		var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
+
+		this.items = $.grep(this.items, function (item) {
+			for (var j=0; j < list.length; j++) {
+				if(list[j] === item.item[0]) {
+					return false;
+				}
+			}
+			return true;
+		});
+
+	},
+
+	_refreshItems: function(event) {
+
+		this.items = [];
+		this.containers = [this];
+
+		var i, j, cur, inst, targetData, _queries, item, queriesLength,
+			items = this.items,
+			queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
+			connectWith = this._connectWith();
+
+		if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
+			for (i = connectWith.length - 1; i >= 0; i--){
+				cur = $(connectWith[i], this.document[0]);
+				for (j = cur.length - 1; j >= 0; j--){
+					inst = $.data(cur[j], this.widgetFullName);
+					if(inst && inst !== this && !inst.options.disabled) {
+						queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
+						this.containers.push(inst);
+					}
+				}
+			}
+		}
+
+		for (i = queries.length - 1; i >= 0; i--) {
+			targetData = queries[i][1];
+			_queries = queries[i][0];
+
+			for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
+				item = $(_queries[j]);
+
+				item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
+
+				items.push({
+					item: item,
+					instance: targetData,
+					width: 0, height: 0,
+					left: 0, top: 0
+				});
+			}
+		}
+
+	},
+
+	refreshPositions: function(fast) {
+
+		// Determine whether items are being displayed horizontally
+		this.floating = this.items.length ?
+			this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
+			false;
+
+		//This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
+		if(this.offsetParent && this.helper) {
+			this.offset.parent = this._getParentOffset();
+		}
+
+		var i, item, t, p;
+
+		for (i = this.items.length - 1; i >= 0; i--){
+			item = this.items[i];
+
+			//We ignore calculating positions of all connected containers when we're not over them
+			if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
+				continue;
+			}
+
+			t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
+
+			if (!fast) {
+				item.width = t.outerWidth();
+				item.height = t.outerHeight();
+			}
+
+			p = t.offset();
+			item.left = p.left;
+			item.top = p.top;
+		}
+
+		if(this.options.custom && this.options.custom.refreshContainers) {
+			this.options.custom.refreshContainers.call(this);
+		} else {
+			for (i = this.containers.length - 1; i >= 0; i--){
+				p = this.containers[i].element.offset();
+				this.containers[i].containerCache.left = p.left;
+				this.containers[i].containerCache.top = p.top;
+				this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
+				this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
+			}
+		}
+
+		return this;
+	},
+
+	_createPlaceholder: function(that) {
+		that = that || this;
+		var className,
+			o = that.options;
+
+		if(!o.placeholder || o.placeholder.constructor === String) {
+			className = o.placeholder;
+			o.placeholder = {
+				element: function() {
+
+					var nodeName = that.currentItem[0].nodeName.toLowerCase(),
+						element = $( "<" + nodeName + ">", that.document[0] )
+							.addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
+							.removeClass("ui-sortable-helper");
+
+					if ( nodeName === "tbody" ) {
+						that._createTrPlaceholder(
+							that.currentItem.find( "tr" ).eq( 0 ),
+							$( "<tr>", that.document[ 0 ] ).appendTo( element )
+						);
+					} else if ( nodeName === "tr" ) {
+						that._createTrPlaceholder( that.currentItem, element );
+					} else if ( nodeName === "img" ) {
+						element.attr( "src", that.currentItem.attr( "src" ) );
+					}
+
+					if ( !className ) {
+						element.css( "visibility", "hidden" );
+					}
+
+					return element;
+				},
+				update: function(container, p) {
+
+					// 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
+					// 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
+					if(className && !o.forcePlaceholderSize) {
+						return;
+					}
+
+					//If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
+					if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
+					if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
+				}
+			};
+		}
+
+		//Create the placeholder
+		that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
+
+		//Append it after the actual current item
+		that.currentItem.after(that.placeholder);
+
+		//Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
+		o.placeholder.update(that, that.placeholder);
+
+	},
+
+	_createTrPlaceholder: function( sourceTr, targetTr ) {
+		var that = this;
+
+		sourceTr.children().each(function() {
+			$( "<td>&#160;</td>", that.document[ 0 ] )
+				.attr( "colspan", $( this ).attr( "colspan" ) || 1 )
+				.appendTo( targetTr );
+		});
+	},
+
+	_contactContainers: function(event) {
+		var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis,
+			innermostContainer = null,
+			innermostIndex = null;
+
+		// get innermost container that intersects with item
+		for (i = this.containers.length - 1; i >= 0; i--) {
+
+			// never consider a container that's located within the item itself
+			if($.contains(this.currentItem[0], this.containers[i].element[0])) {
+				continue;
+			}
+
+			if(this._intersectsWith(this.containers[i].containerCache)) {
+
+				// if we've already found a container and it's more "inner" than this, then continue
+				if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
+					continue;
+				}
+
+				innermostContainer = this.containers[i];
+				innermostIndex = i;
+
+			} else {
+				// container doesn't intersect. trigger "out" event if necessary
+				if(this.containers[i].containerCache.over) {
+					this.containers[i]._trigger("out", event, this._uiHash(this));
+					this.containers[i].containerCache.over = 0;
+				}
+			}
+
+		}
+
+		// if no intersecting containers found, return
+		if(!innermostContainer) {
+			return;
+		}
+
+		// move the item into the container if it's not there already
+		if(this.containers.length === 1) {
+			if (!this.containers[innermostIndex].containerCache.over) {
+				this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+				this.containers[innermostIndex].containerCache.over = 1;
+			}
+		} else {
+
+			//When entering a new container, we will find the item with the least distance and append our item near it
+			dist = 10000;
+			itemWithLeastDistance = null;
+			floating = innermostContainer.floating || this._isFloating(this.currentItem);
+			posProperty = floating ? "left" : "top";
+			sizeProperty = floating ? "width" : "height";
+			axis = floating ? "clientX" : "clientY";
+
+			for (j = this.items.length - 1; j >= 0; j--) {
+				if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
+					continue;
+				}
+				if(this.items[j].item[0] === this.currentItem[0]) {
+					continue;
+				}
+
+				cur = this.items[j].item.offset()[posProperty];
+				nearBottom = false;
+				if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
+					nearBottom = true;
+				}
+
+				if ( Math.abs( event[ axis ] - cur ) < dist ) {
+					dist = Math.abs( event[ axis ] - cur );
+					itemWithLeastDistance = this.items[ j ];
+					this.direction = nearBottom ? "up": "down";
+				}
+			}
+
+			//Check if dropOnEmpty is enabled
+			if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
+				return;
+			}
+
+			if(this.currentContainer === this.containers[innermostIndex]) {
+				if ( !this.currentContainer.containerCache.over ) {
+					this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
+					this.currentContainer.containerCache.over = 1;
+				}
+				return;
+			}
+
+			itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
+			this._trigger("change", event, this._uiHash());
+			this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
+			this.currentContainer = this.containers[innermostIndex];
+
+			//Update the placeholder
+			this.options.placeholder.update(this.currentContainer, this.placeholder);
+
+			this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+			this.containers[innermostIndex].containerCache.over = 1;
+		}
+
+
+	},
+
+	_createHelper: function(event) {
+
+		var o = this.options,
+			helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
+
+		//Add the helper to the DOM if that didn't happen already
+		if(!helper.parents("body").length) {
+			$(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
+		}
+
+		if(helper[0] === this.currentItem[0]) {
+			this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
+		}
+
+		if(!helper[0].style.width || o.forceHelperSize) {
+			helper.width(this.currentItem.width());
+		}
+		if(!helper[0].style.height || o.forceHelperSize) {
+			helper.height(this.currentItem.height());
+		}
+
+		return helper;
+
+	},
+
+	_adjustOffsetFromHelper: function(obj) {
+		if (typeof obj === "string") {
+			obj = obj.split(" ");
+		}
+		if ($.isArray(obj)) {
+			obj = {left: +obj[0], top: +obj[1] || 0};
+		}
+		if ("left" in obj) {
+			this.offset.click.left = obj.left + this.margins.left;
+		}
+		if ("right" in obj) {
+			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+		}
+		if ("top" in obj) {
+			this.offset.click.top = obj.top + this.margins.top;
+		}
+		if ("bottom" in obj) {
+			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+		}
+	},
+
+	_getParentOffset: function() {
+
+
+		//Get the offsetParent and cache its position
+		this.offsetParent = this.helper.offsetParent();
+		var po = this.offsetParent.offset();
+
+		// This is a special case where we need to modify a offset calculated on start, since the following happened:
+		// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+		//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+		if(this.cssPosition === "absolute" && this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+			po.left += this.scrollParent.scrollLeft();
+			po.top += this.scrollParent.scrollTop();
+		}
+
+		// This needs to be actually done for all browsers, since pageX/pageY includes this information
+		// with an ugly IE fix
+		if( this.offsetParent[0] === this.document[0].body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
+			po = { top: 0, left: 0 };
+		}
+
+		return {
+			top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+			left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+		};
+
+	},
+
+	_getRelativeOffset: function() {
+
+		if(this.cssPosition === "relative") {
+			var p = this.currentItem.position();
+			return {
+				top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+				left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+			};
+		} else {
+			return { top: 0, left: 0 };
+		}
+
+	},
+
+	_cacheMargins: function() {
+		this.margins = {
+			left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
+			top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
+		};
+	},
+
+	_cacheHelperProportions: function() {
+		this.helperProportions = {
+			width: this.helper.outerWidth(),
+			height: this.helper.outerHeight()
+		};
+	},
+
+	_setContainment: function() {
+
+		var ce, co, over,
+			o = this.options;
+		if(o.containment === "parent") {
+			o.containment = this.helper[0].parentNode;
+		}
+		if(o.containment === "document" || o.containment === "window") {
+			this.containment = [
+				0 - this.offset.relative.left - this.offset.parent.left,
+				0 - this.offset.relative.top - this.offset.parent.top,
+				o.containment === "document" ? this.document.width() : this.window.width() - this.helperProportions.width - this.margins.left,
+				(o.containment === "document" ? this.document.width() : this.window.height() || this.document[0].body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
+			];
+		}
+
+		if(!(/^(document|window|parent)$/).test(o.containment)) {
+			ce = $(o.containment)[0];
+			co = $(o.containment).offset();
+			over = ($(ce).css("overflow") !== "hidden");
+
+			this.containment = [
+				co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
+				co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
+				co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
+				co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
+			];
+		}
+
+	},
+
+	_convertPositionTo: function(d, pos) {
+
+		if(!pos) {
+			pos = this.position;
+		}
+		var mod = d === "absolute" ? 1 : -1,
+			scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
+			scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+		return {
+			top: (
+				pos.top	+																// The absolute mouse position
+				this.offset.relative.top * mod +										// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.top * mod -											// The offsetParent's offset without borders (offset + border)
+				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
+			),
+			left: (
+				pos.left +																// The absolute mouse position
+				this.offset.relative.left * mod +										// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.left * mod	-										// The offsetParent's offset without borders (offset + border)
+				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
+			)
+		};
+
+	},
+
+	_generatePosition: function(event) {
+
+		var top, left,
+			o = this.options,
+			pageX = event.pageX,
+			pageY = event.pageY,
+			scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+		// This is another very weird special case that only happens for relative elements:
+		// 1. If the css position is relative
+		// 2. and the scroll parent is the document or similar to the offset parent
+		// we have to refresh the relative offset during the scroll so there are no jumps
+		if(this.cssPosition === "relative" && !(this.scrollParent[0] !== this.document[0] && this.scrollParent[0] !== this.offsetParent[0])) {
+			this.offset.relative = this._getRelativeOffset();
+		}
+
+		/*
+		 * - Position constraining -
+		 * Constrain the position to a mix of grid, containment.
+		 */
+
+		if(this.originalPosition) { //If we are not dragging yet, we won't check for options
+
+			if(this.containment) {
+				if(event.pageX - this.offset.click.left < this.containment[0]) {
+					pageX = this.containment[0] + this.offset.click.left;
+				}
+				if(event.pageY - this.offset.click.top < this.containment[1]) {
+					pageY = this.containment[1] + this.offset.click.top;
+				}
+				if(event.pageX - this.offset.click.left > this.containment[2]) {
+					pageX = this.containment[2] + this.offset.click.left;
+				}
+				if(event.pageY - this.offset.click.top > this.containment[3]) {
+					pageY = this.containment[3] + this.offset.click.top;
+				}
+			}
+
+			if(o.grid) {
+				top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
+				pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+				left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
+				pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+			}
+
+		}
+
+		return {
+			top: (
+				pageY -																// The absolute mouse position
+				this.offset.click.top -													// Click offset (relative to the element)
+				this.offset.relative.top	-											// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.top +												// The offsetParent's offset without borders (offset + border)
+				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
+			),
+			left: (
+				pageX -																// The absolute mouse position
+				this.offset.click.left -												// Click offset (relative to the element)
+				this.offset.relative.left	-											// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.left +												// The offsetParent's offset without borders (offset + border)
+				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
+			)
+		};
+
+	},
+
+	_rearrange: function(event, i, a, hardRefresh) {
+
+		a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling));
+
+		//Various things done here to improve the performance:
+		// 1. we create a setTimeout, that calls refreshPositions
+		// 2. on the instance, we have a counter variable, that get's higher after every append
+		// 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
+		// 4. this lets only the last addition to the timeout stack through
+		this.counter = this.counter ? ++this.counter : 1;
+		var counter = this.counter;
+
+		this._delay(function() {
+			if(counter === this.counter) {
+				this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
+			}
+		});
+
+	},
+
+	_clear: function(event, noPropagation) {
+
+		this.reverting = false;
+		// We delay all events that have to be triggered to after the point where the placeholder has been removed and
+		// everything else normalized again
+		var i,
+			delayedTriggers = [];
+
+		// We first have to update the dom position of the actual currentItem
+		// Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
+		if(!this._noFinalSort && this.currentItem.parent().length) {
+			this.placeholder.before(this.currentItem);
+		}
+		this._noFinalSort = null;
+
+		if(this.helper[0] === this.currentItem[0]) {
+			for(i in this._storedCSS) {
+				if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
+					this._storedCSS[i] = "";
+				}
+			}
+			this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+		} else {
+			this.currentItem.show();
+		}
+
+		if(this.fromOutside && !noPropagation) {
+			delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
+		}
+		if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
+			delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
+		}
+
+		// Check if the items Container has Changed and trigger appropriate
+		// events.
+		if (this !== this.currentContainer) {
+			if(!noPropagation) {
+				delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
+				delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); };  }).call(this, this.currentContainer));
+				delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this));  }; }).call(this, this.currentContainer));
+			}
+		}
+
+
+		//Post events to containers
+		function delayEvent( type, instance, container ) {
+			return function( event ) {
+				container._trigger( type, event, instance._uiHash( instance ) );
+			};
+		}
+		for (i = this.containers.length - 1; i >= 0; i--){
+			if (!noPropagation) {
+				delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
+			}
+			if(this.containers[i].containerCache.over) {
+				delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
+				this.containers[i].containerCache.over = 0;
+			}
+		}
+
+		//Do what was originally in plugins
+		if ( this.storedCursor ) {
+			this.document.find( "body" ).css( "cursor", this.storedCursor );
+			this.storedStylesheet.remove();
+		}
+		if(this._storedOpacity) {
+			this.helper.css("opacity", this._storedOpacity);
+		}
+		if(this._storedZIndex) {
+			this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
+		}
+
+		this.dragging = false;
+
+		if(!noPropagation) {
+			this._trigger("beforeStop", event, this._uiHash());
+		}
+
+		//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+		this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+
+		if ( !this.cancelHelperRemoval ) {
+			if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
+				this.helper.remove();
+			}
+			this.helper = null;
+		}
+
+		if(!noPropagation) {
+			for (i=0; i < delayedTriggers.length; i++) {
+				delayedTriggers[i].call(this, event);
+			} //Trigger all delayed events
+			this._trigger("stop", event, this._uiHash());
+		}
+
+		this.fromOutside = false;
+		return !this.cancelHelperRemoval;
+
+	},
+
+	_trigger: function() {
+		if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
+			this.cancel();
+		}
+	},
+
+	_uiHash: function(_inst) {
+		var inst = _inst || this;
+		return {
+			helper: inst.helper,
+			placeholder: inst.placeholder || $([]),
+			position: inst.position,
+			originalPosition: inst.originalPosition,
+			offset: inst.positionAbs,
+			item: inst.currentItem,
+			sender: _inst ? _inst.element : null
+		};
+	}
+
+});
+
+
+/*!
+ * jQuery UI Accordion 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/accordion/
+ */
+
+
+var accordion = $.widget( "ui.accordion", {
+	version: "1.11.4",
+	options: {
+		active: 0,
+		animate: {},
+		collapsible: false,
+		event: "click",
+		header: "> li > :first-child,> :not(li):even",
+		heightStyle: "auto",
+		icons: {
+			activeHeader: "ui-icon-triangle-1-s",
+			header: "ui-icon-triangle-1-e"
+		},
+
+		// callbacks
+		activate: null,
+		beforeActivate: null
+	},
+
+	hideProps: {
+		borderTopWidth: "hide",
+		borderBottomWidth: "hide",
+		paddingTop: "hide",
+		paddingBottom: "hide",
+		height: "hide"
+	},
+
+	showProps: {
+		borderTopWidth: "show",
+		borderBottomWidth: "show",
+		paddingTop: "show",
+		paddingBottom: "show",
+		height: "show"
+	},
+
+	_create: function() {
+		var options = this.options;
+		this.prevShow = this.prevHide = $();
+		this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
+			// ARIA
+			.attr( "role", "tablist" );
+
+		// don't allow collapsible: false and active: false / null
+		if ( !options.collapsible && (options.active === false || options.active == null) ) {
+			options.active = 0;
+		}
+
+		this._processPanels();
+		// handle negative values
+		if ( options.active < 0 ) {
+			options.active += this.headers.length;
+		}
+		this._refresh();
+	},
+
+	_getCreateEventData: function() {
+		return {
+			header: this.active,
+			panel: !this.active.length ? $() : this.active.next()
+		};
+	},
+
+	_createIcons: function() {
+		var icons = this.options.icons;
+		if ( icons ) {
+			$( "<span>" )
+				.addClass( "ui-accordion-header-icon ui-icon " + icons.header )
+				.prependTo( this.headers );
+			this.active.children( ".ui-accordion-header-icon" )
+				.removeClass( icons.header )
+				.addClass( icons.activeHeader );
+			this.headers.addClass( "ui-accordion-icons" );
+		}
+	},
+
+	_destroyIcons: function() {
+		this.headers
+			.removeClass( "ui-accordion-icons" )
+			.children( ".ui-accordion-header-icon" )
+				.remove();
+	},
+
+	_destroy: function() {
+		var contents;
+
+		// clean up main element
+		this.element
+			.removeClass( "ui-accordion ui-widget ui-helper-reset" )
+			.removeAttr( "role" );
+
+		// clean up headers
+		this.headers
+			.removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " +
+				"ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
+			.removeAttr( "role" )
+			.removeAttr( "aria-expanded" )
+			.removeAttr( "aria-selected" )
+			.removeAttr( "aria-controls" )
+			.removeAttr( "tabIndex" )
+			.removeUniqueId();
+
+		this._destroyIcons();
+
+		// clean up content panels
+		contents = this.headers.next()
+			.removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " +
+				"ui-accordion-content ui-accordion-content-active ui-state-disabled" )
+			.css( "display", "" )
+			.removeAttr( "role" )
+			.removeAttr( "aria-hidden" )
+			.removeAttr( "aria-labelledby" )
+			.removeUniqueId();
+
+		if ( this.options.heightStyle !== "content" ) {
+			contents.css( "height", "" );
+		}
+	},
+
+	_setOption: function( key, value ) {
+		if ( key === "active" ) {
+			// _activate() will handle invalid values and update this.options
+			this._activate( value );
+			return;
+		}
+
+		if ( key === "event" ) {
+			if ( this.options.event ) {
+				this._off( this.headers, this.options.event );
+			}
+			this._setupEvents( value );
+		}
+
+		this._super( key, value );
+
+		// setting collapsible: false while collapsed; open first panel
+		if ( key === "collapsible" && !value && this.options.active === false ) {
+			this._activate( 0 );
+		}
+
+		if ( key === "icons" ) {
+			this._destroyIcons();
+			if ( value ) {
+				this._createIcons();
+			}
+		}
+
+		// #5332 - opacity doesn't cascade to positioned elements in IE
+		// so we need to add the disabled class to the headers and panels
+		if ( key === "disabled" ) {
+			this.element
+				.toggleClass( "ui-state-disabled", !!value )
+				.attr( "aria-disabled", value );
+			this.headers.add( this.headers.next() )
+				.toggleClass( "ui-state-disabled", !!value );
+		}
+	},
+
+	_keydown: function( event ) {
+		if ( event.altKey || event.ctrlKey ) {
+			return;
+		}
+
+		var keyCode = $.ui.keyCode,
+			length = this.headers.length,
+			currentIndex = this.headers.index( event.target ),
+			toFocus = false;
+
+		switch ( event.keyCode ) {
+			case keyCode.RIGHT:
+			case keyCode.DOWN:
+				toFocus = this.headers[ ( currentIndex + 1 ) % length ];
+				break;
+			case keyCode.LEFT:
+			case keyCode.UP:
+				toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
+				break;
+			case keyCode.SPACE:
+			case keyCode.ENTER:
+				this._eventHandler( event );
+				break;
+			case keyCode.HOME:
+				toFocus = this.headers[ 0 ];
+				break;
+			case keyCode.END:
+				toFocus = this.headers[ length - 1 ];
+				break;
+		}
+
+		if ( toFocus ) {
+			$( event.target ).attr( "tabIndex", -1 );
+			$( toFocus ).attr( "tabIndex", 0 );
+			toFocus.focus();
+			event.preventDefault();
+		}
+	},
+
+	_panelKeyDown: function( event ) {
+		if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
+			$( event.currentTarget ).prev().focus();
+		}
+	},
+
+	refresh: function() {
+		var options = this.options;
+		this._processPanels();
+
+		// was collapsed or no panel
+		if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
+			options.active = false;
+			this.active = $();
+		// active false only when collapsible is true
+		} else if ( options.active === false ) {
+			this._activate( 0 );
+		// was active, but active panel is gone
+		} else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
+			// all remaining panel are disabled
+			if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
+				options.active = false;
+				this.active = $();
+			// activate previous panel
+			} else {
+				this._activate( Math.max( 0, options.active - 1 ) );
+			}
+		// was active, active panel still exists
+		} else {
+			// make sure active index is correct
+			options.active = this.headers.index( this.active );
+		}
+
+		this._destroyIcons();
+
+		this._refresh();
+	},
+
+	_processPanels: function() {
+		var prevHeaders = this.headers,
+			prevPanels = this.panels;
+
+		this.headers = this.element.find( this.options.header )
+			.addClass( "ui-accordion-header ui-state-default ui-corner-all" );
+
+		this.panels = this.headers.next()
+			.addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
+			.filter( ":not(.ui-accordion-content-active)" )
+			.hide();
+
+		// Avoid memory leaks (#10056)
+		if ( prevPanels ) {
+			this._off( prevHeaders.not( this.headers ) );
+			this._off( prevPanels.not( this.panels ) );
+		}
+	},
+
+	_refresh: function() {
+		var maxHeight,
+			options = this.options,
+			heightStyle = options.heightStyle,
+			parent = this.element.parent();
+
+		this.active = this._findActive( options.active )
+			.addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
+			.removeClass( "ui-corner-all" );
+		this.active.next()
+			.addClass( "ui-accordion-content-active" )
+			.show();
+
+		this.headers
+			.attr( "role", "tab" )
+			.each(function() {
+				var header = $( this ),
+					headerId = header.uniqueId().attr( "id" ),
+					panel = header.next(),
+					panelId = panel.uniqueId().attr( "id" );
+				header.attr( "aria-controls", panelId );
+				panel.attr( "aria-labelledby", headerId );
+			})
+			.next()
+				.attr( "role", "tabpanel" );
+
+		this.headers
+			.not( this.active )
+			.attr({
+				"aria-selected": "false",
+				"aria-expanded": "false",
+				tabIndex: -1
+			})
+			.next()
+				.attr({
+					"aria-hidden": "true"
+				})
+				.hide();
+
+		// make sure at least one header is in the tab order
+		if ( !this.active.length ) {
+			this.headers.eq( 0 ).attr( "tabIndex", 0 );
+		} else {
+			this.active.attr({
+				"aria-selected": "true",
+				"aria-expanded": "true",
+				tabIndex: 0
+			})
+			.next()
+				.attr({
+					"aria-hidden": "false"
+				});
+		}
+
+		this._createIcons();
+
+		this._setupEvents( options.event );
+
+		if ( heightStyle === "fill" ) {
+			maxHeight = parent.height();
+			this.element.siblings( ":visible" ).each(function() {
+				var elem = $( this ),
+					position = elem.css( "position" );
+
+				if ( position === "absolute" || position === "fixed" ) {
+					return;
+				}
+				maxHeight -= elem.outerHeight( true );
+			});
+
+			this.headers.each(function() {
+				maxHeight -= $( this ).outerHeight( true );
+			});
+
+			this.headers.next()
+				.each(function() {
+					$( this ).height( Math.max( 0, maxHeight -
+						$( this ).innerHeight() + $( this ).height() ) );
+				})
+				.css( "overflow", "auto" );
+		} else if ( heightStyle === "auto" ) {
+			maxHeight = 0;
+			this.headers.next()
+				.each(function() {
+					maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
+				})
+				.height( maxHeight );
+		}
+	},
+
+	_activate: function( index ) {
+		var active = this._findActive( index )[ 0 ];
+
+		// trying to activate the already active panel
+		if ( active === this.active[ 0 ] ) {
+			return;
+		}
+
+		// trying to collapse, simulate a click on the currently active header
+		active = active || this.active[ 0 ];
+
+		this._eventHandler({
+			target: active,
+			currentTarget: active,
+			preventDefault: $.noop
+		});
+	},
+
+	_findActive: function( selector ) {
+		return typeof selector === "number" ? this.headers.eq( selector ) : $();
+	},
+
+	_setupEvents: function( event ) {
+		var events = {
+			keydown: "_keydown"
+		};
+		if ( event ) {
+			$.each( event.split( " " ), function( index, eventName ) {
+				events[ eventName ] = "_eventHandler";
+			});
+		}
+
+		this._off( this.headers.add( this.headers.next() ) );
+		this._on( this.headers, events );
+		this._on( this.headers.next(), { keydown: "_panelKeyDown" });
+		this._hoverable( this.headers );
+		this._focusable( this.headers );
+	},
+
+	_eventHandler: function( event ) {
+		var options = this.options,
+			active = this.active,
+			clicked = $( event.currentTarget ),
+			clickedIsActive = clicked[ 0 ] === active[ 0 ],
+			collapsing = clickedIsActive && options.collapsible,
+			toShow = collapsing ? $() : clicked.next(),
+			toHide = active.next(),
+			eventData = {
+				oldHeader: active,
+				oldPanel: toHide,
+				newHeader: collapsing ? $() : clicked,
+				newPanel: toShow
+			};
+
+		event.preventDefault();
+
+		if (
+				// click on active header, but not collapsible
+				( clickedIsActive && !options.collapsible ) ||
+				// allow canceling activation
+				( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+			return;
+		}
+
+		options.active = collapsing ? false : this.headers.index( clicked );
+
+		// when the call to ._toggle() comes after the class changes
+		// it causes a very odd bug in IE 8 (see #6720)
+		this.active = clickedIsActive ? $() : clicked;
+		this._toggle( eventData );
+
+		// switch classes
+		// corner classes on the previously active header stay after the animation
+		active.removeClass( "ui-accordion-header-active ui-state-active" );
+		if ( options.icons ) {
+			active.children( ".ui-accordion-header-icon" )
+				.removeClass( options.icons.activeHeader )
+				.addClass( options.icons.header );
+		}
+
+		if ( !clickedIsActive ) {
+			clicked
+				.removeClass( "ui-corner-all" )
+				.addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
+			if ( options.icons ) {
+				clicked.children( ".ui-accordion-header-icon" )
+					.removeClass( options.icons.header )
+					.addClass( options.icons.activeHeader );
+			}
+
+			clicked
+				.next()
+				.addClass( "ui-accordion-content-active" );
+		}
+	},
+
+	_toggle: function( data ) {
+		var toShow = data.newPanel,
+			toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
+
+		// handle activating a panel during the animation for another activation
+		this.prevShow.add( this.prevHide ).stop( true, true );
+		this.prevShow = toShow;
+		this.prevHide = toHide;
+
+		if ( this.options.animate ) {
+			this._animate( toShow, toHide, data );
+		} else {
+			toHide.hide();
+			toShow.show();
+			this._toggleComplete( data );
+		}
+
+		toHide.attr({
+			"aria-hidden": "true"
+		});
+		toHide.prev().attr({
+			"aria-selected": "false",
+			"aria-expanded": "false"
+		});
+		// if we're switching panels, remove the old header from the tab order
+		// if we're opening from collapsed state, remove the previous header from the tab order
+		// if we're collapsing, then keep the collapsing header in the tab order
+		if ( toShow.length && toHide.length ) {
+			toHide.prev().attr({
+				"tabIndex": -1,
+				"aria-expanded": "false"
+			});
+		} else if ( toShow.length ) {
+			this.headers.filter(function() {
+				return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
+			})
+			.attr( "tabIndex", -1 );
+		}
+
+		toShow
+			.attr( "aria-hidden", "false" )
+			.prev()
+				.attr({
+					"aria-selected": "true",
+					"aria-expanded": "true",
+					tabIndex: 0
+				});
+	},
+
+	_animate: function( toShow, toHide, data ) {
+		var total, easing, duration,
+			that = this,
+			adjust = 0,
+			boxSizing = toShow.css( "box-sizing" ),
+			down = toShow.length &&
+				( !toHide.length || ( toShow.index() < toHide.index() ) ),
+			animate = this.options.animate || {},
+			options = down && animate.down || animate,
+			complete = function() {
+				that._toggleComplete( data );
+			};
+
+		if ( typeof options === "number" ) {
+			duration = options;
+		}
+		if ( typeof options === "string" ) {
+			easing = options;
+		}
+		// fall back from options to animation in case of partial down settings
+		easing = easing || options.easing || animate.easing;
+		duration = duration || options.duration || animate.duration;
+
+		if ( !toHide.length ) {
+			return toShow.animate( this.showProps, duration, easing, complete );
+		}
+		if ( !toShow.length ) {
+			return toHide.animate( this.hideProps, duration, easing, complete );
+		}
+
+		total = toShow.show().outerHeight();
+		toHide.animate( this.hideProps, {
+			duration: duration,
+			easing: easing,
+			step: function( now, fx ) {
+				fx.now = Math.round( now );
+			}
+		});
+		toShow
+			.hide()
+			.animate( this.showProps, {
+				duration: duration,
+				easing: easing,
+				complete: complete,
+				step: function( now, fx ) {
+					fx.now = Math.round( now );
+					if ( fx.prop !== "height" ) {
+						if ( boxSizing === "content-box" ) {
+							adjust += fx.now;
+						}
+					} else if ( that.options.heightStyle !== "content" ) {
+						fx.now = Math.round( total - toHide.outerHeight() - adjust );
+						adjust = 0;
+					}
+				}
+			});
+	},
+
+	_toggleComplete: function( data ) {
+		var toHide = data.oldPanel;
+
+		toHide
+			.removeClass( "ui-accordion-content-active" )
+			.prev()
+				.removeClass( "ui-corner-top" )
+				.addClass( "ui-corner-all" );
+
+		// Work around for rendering bug in IE (#5421)
+		if ( toHide.length ) {
+			toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
+		}
+		this._trigger( "activate", null, data );
+	}
+});
+
+
+/*!
+ * jQuery UI Menu 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/menu/
+ */
+
+
+var menu = $.widget( "ui.menu", {
+	version: "1.11.4",
+	defaultElement: "<ul>",
+	delay: 300,
+	options: {
+		icons: {
+			submenu: "ui-icon-carat-1-e"
+		},
+		items: "> *",
+		menus: "ul",
+		position: {
+			my: "left-1 top",
+			at: "right top"
+		},
+		role: "menu",
+
+		// callbacks
+		blur: null,
+		focus: null,
+		select: null
+	},
+
+	_create: function() {
+		this.activeMenu = this.element;
+
+		// Flag used to prevent firing of the click handler
+		// as the event bubbles up through nested menus
+		this.mouseHandled = false;
+		this.element
+			.uniqueId()
+			.addClass( "ui-menu ui-widget ui-widget-content" )
+			.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
+			.attr({
+				role: this.options.role,
+				tabIndex: 0
+			});
+
+		if ( this.options.disabled ) {
+			this.element
+				.addClass( "ui-state-disabled" )
+				.attr( "aria-disabled", "true" );
+		}
+
+		this._on({
+			// Prevent focus from sticking to links inside menu after clicking
+			// them (focus should always stay on UL during navigation).
+			"mousedown .ui-menu-item": function( event ) {
+				event.preventDefault();
+			},
+			"click .ui-menu-item": function( event ) {
+				var target = $( event.target );
+				if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
+					this.select( event );
+
+					// Only set the mouseHandled flag if the event will bubble, see #9469.
+					if ( !event.isPropagationStopped() ) {
+						this.mouseHandled = true;
+					}
+
+					// Open submenu on click
+					if ( target.has( ".ui-menu" ).length ) {
+						this.expand( event );
+					} else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
+
+						// Redirect focus to the menu
+						this.element.trigger( "focus", [ true ] );
+
+						// If the active item is on the top level, let it stay active.
+						// Otherwise, blur the active item since it is no longer visible.
+						if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
+							clearTimeout( this.timer );
+						}
+					}
+				}
+			},
+			"mouseenter .ui-menu-item": function( event ) {
+				// Ignore mouse events while typeahead is active, see #10458.
+				// Prevents focusing the wrong item when typeahead causes a scroll while the mouse
+				// is over an item in the menu
+				if ( this.previousFilter ) {
+					return;
+				}
+				var target = $( event.currentTarget );
+				// Remove ui-state-active class from siblings of the newly focused menu item
+				// to avoid a jump caused by adjacent elements both having a class with a border
+				target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" );
+				this.focus( event, target );
+			},
+			mouseleave: "collapseAll",
+			"mouseleave .ui-menu": "collapseAll",
+			focus: function( event, keepActiveItem ) {
+				// If there's already an active item, keep it active
+				// If not, activate the first item
+				var item = this.active || this.element.find( this.options.items ).eq( 0 );
+
+				if ( !keepActiveItem ) {
+					this.focus( event, item );
+				}
+			},
+			blur: function( event ) {
+				this._delay(function() {
+					if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
+						this.collapseAll( event );
+					}
+				});
+			},
+			keydown: "_keydown"
+		});
+
+		this.refresh();
+
+		// Clicks outside of a menu collapse any open menus
+		this._on( this.document, {
+			click: function( event ) {
+				if ( this._closeOnDocumentClick( event ) ) {
+					this.collapseAll( event );
+				}
+
+				// Reset the mouseHandled flag
+				this.mouseHandled = false;
+			}
+		});
+	},
+
+	_destroy: function() {
+		// Destroy (sub)menus
+		this.element
+			.removeAttr( "aria-activedescendant" )
+			.find( ".ui-menu" ).addBack()
+				.removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" )
+				.removeAttr( "role" )
+				.removeAttr( "tabIndex" )
+				.removeAttr( "aria-labelledby" )
+				.removeAttr( "aria-expanded" )
+				.removeAttr( "aria-hidden" )
+				.removeAttr( "aria-disabled" )
+				.removeUniqueId()
+				.show();
+
+		// Destroy menu items
+		this.element.find( ".ui-menu-item" )
+			.removeClass( "ui-menu-item" )
+			.removeAttr( "role" )
+			.removeAttr( "aria-disabled" )
+			.removeUniqueId()
+			.removeClass( "ui-state-hover" )
+			.removeAttr( "tabIndex" )
+			.removeAttr( "role" )
+			.removeAttr( "aria-haspopup" )
+			.children().each( function() {
+				var elem = $( this );
+				if ( elem.data( "ui-menu-submenu-carat" ) ) {
+					elem.remove();
+				}
+			});
+
+		// Destroy menu dividers
+		this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
+	},
+
+	_keydown: function( event ) {
+		var match, prev, character, skip,
+			preventDefault = true;
+
+		switch ( event.keyCode ) {
+		case $.ui.keyCode.PAGE_UP:
+			this.previousPage( event );
+			break;
+		case $.ui.keyCode.PAGE_DOWN:
+			this.nextPage( event );
+			break;
+		case $.ui.keyCode.HOME:
+			this._move( "first", "first", event );
+			break;
+		case $.ui.keyCode.END:
+			this._move( "last", "last", event );
+			break;
+		case $.ui.keyCode.UP:
+			this.previous( event );
+			break;
+		case $.ui.keyCode.DOWN:
+			this.next( event );
+			break;
+		case $.ui.keyCode.LEFT:
+			this.collapse( event );
+			break;
+		case $.ui.keyCode.RIGHT:
+			if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
+				this.expand( event );
+			}
+			break;
+		case $.ui.keyCode.ENTER:
+		case $.ui.keyCode.SPACE:
+			this._activate( event );
+			break;
+		case $.ui.keyCode.ESCAPE:
+			this.collapse( event );
+			break;
+		default:
+			preventDefault = false;
+			prev = this.previousFilter || "";
+			character = String.fromCharCode( event.keyCode );
+			skip = false;
+
+			clearTimeout( this.filterTimer );
+
+			if ( character === prev ) {
+				skip = true;
+			} else {
+				character = prev + character;
+			}
+
+			match = this._filterMenuItems( character );
+			match = skip && match.index( this.active.next() ) !== -1 ?
+				this.active.nextAll( ".ui-menu-item" ) :
+				match;
+
+			// If no matches on the current filter, reset to the last character pressed
+			// to move down the menu to the first item that starts with that character
+			if ( !match.length ) {
+				character = String.fromCharCode( event.keyCode );
+				match = this._filterMenuItems( character );
+			}
+
+			if ( match.length ) {
+				this.focus( event, match );
+				this.previousFilter = character;
+				this.filterTimer = this._delay(function() {
+					delete this.previousFilter;
+				}, 1000 );
+			} else {
+				delete this.previousFilter;
+			}
+		}
+
+		if ( preventDefault ) {
+			event.preventDefault();
+		}
+	},
+
+	_activate: function( event ) {
+		if ( !this.active.is( ".ui-state-disabled" ) ) {
+			if ( this.active.is( "[aria-haspopup='true']" ) ) {
+				this.expand( event );
+			} else {
+				this.select( event );
+			}
+		}
+	},
+
+	refresh: function() {
+		var menus, items,
+			that = this,
+			icon = this.options.icons.submenu,
+			submenus = this.element.find( this.options.menus );
+
+		this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
+
+		// Initialize nested menus
+		submenus.filter( ":not(.ui-menu)" )
+			.addClass( "ui-menu ui-widget ui-widget-content ui-front" )
+			.hide()
+			.attr({
+				role: this.options.role,
+				"aria-hidden": "true",
+				"aria-expanded": "false"
+			})
+			.each(function() {
+				var menu = $( this ),
+					item = menu.parent(),
+					submenuCarat = $( "<span>" )
+						.addClass( "ui-menu-icon ui-icon " + icon )
+						.data( "ui-menu-submenu-carat", true );
+
+				item
+					.attr( "aria-haspopup", "true" )
+					.prepend( submenuCarat );
+				menu.attr( "aria-labelledby", item.attr( "id" ) );
+			});
+
+		menus = submenus.add( this.element );
+		items = menus.find( this.options.items );
+
+		// Initialize menu-items containing spaces and/or dashes only as dividers
+		items.not( ".ui-menu-item" ).each(function() {
+			var item = $( this );
+			if ( that._isDivider( item ) ) {
+				item.addClass( "ui-widget-content ui-menu-divider" );
+			}
+		});
+
+		// Don't refresh list items that are already adapted
+		items.not( ".ui-menu-item, .ui-menu-divider" )
+			.addClass( "ui-menu-item" )
+			.uniqueId()
+			.attr({
+				tabIndex: -1,
+				role: this._itemRole()
+			});
+
+		// Add aria-disabled attribute to any disabled menu item
+		items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
+
+		// If the active item has been removed, blur the menu
+		if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
+			this.blur();
+		}
+	},
+
+	_itemRole: function() {
+		return {
+			menu: "menuitem",
+			listbox: "option"
+		}[ this.options.role ];
+	},
+
+	_setOption: function( key, value ) {
+		if ( key === "icons" ) {
+			this.element.find( ".ui-menu-icon" )
+				.removeClass( this.options.icons.submenu )
+				.addClass( value.submenu );
+		}
+		if ( key === "disabled" ) {
+			this.element
+				.toggleClass( "ui-state-disabled", !!value )
+				.attr( "aria-disabled", value );
+		}
+		this._super( key, value );
+	},
+
+	focus: function( event, item ) {
+		var nested, focused;
+		this.blur( event, event && event.type === "focus" );
+
+		this._scrollIntoView( item );
+
+		this.active = item.first();
+		focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" );
+		// Only update aria-activedescendant if there's a role
+		// otherwise we assume focus is managed elsewhere
+		if ( this.options.role ) {
+			this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
+		}
+
+		// Highlight active parent menu item, if any
+		this.active
+			.parent()
+			.closest( ".ui-menu-item" )
+			.addClass( "ui-state-active" );
+
+		if ( event && event.type === "keydown" ) {
+			this._close();
+		} else {
+			this.timer = this._delay(function() {
+				this._close();
+			}, this.delay );
+		}
+
+		nested = item.children( ".ui-menu" );
+		if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
+			this._startOpening(nested);
+		}
+		this.activeMenu = item.parent();
+
+		this._trigger( "focus", event, { item: item } );
+	},
+
+	_scrollIntoView: function( item ) {
+		var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
+		if ( this._hasScroll() ) {
+			borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
+			paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
+			offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
+			scroll = this.activeMenu.scrollTop();
+			elementHeight = this.activeMenu.height();
+			itemHeight = item.outerHeight();
+
+			if ( offset < 0 ) {
+				this.activeMenu.scrollTop( scroll + offset );
+			} else if ( offset + itemHeight > elementHeight ) {
+				this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
+			}
+		}
+	},
+
+	blur: function( event, fromFocus ) {
+		if ( !fromFocus ) {
+			clearTimeout( this.timer );
+		}
+
+		if ( !this.active ) {
+			return;
+		}
+
+		this.active.removeClass( "ui-state-focus" );
+		this.active = null;
+
+		this._trigger( "blur", event, { item: this.active } );
+	},
+
+	_startOpening: function( submenu ) {
+		clearTimeout( this.timer );
+
+		// Don't open if already open fixes a Firefox bug that caused a .5 pixel
+		// shift in the submenu position when mousing over the carat icon
+		if ( submenu.attr( "aria-hidden" ) !== "true" ) {
+			return;
+		}
+
+		this.timer = this._delay(function() {
+			this._close();
+			this._open( submenu );
+		}, this.delay );
+	},
+
+	_open: function( submenu ) {
+		var position = $.extend({
+			of: this.active
+		}, this.options.position );
+
+		clearTimeout( this.timer );
+		this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
+			.hide()
+			.attr( "aria-hidden", "true" );
+
+		submenu
+			.show()
+			.removeAttr( "aria-hidden" )
+			.attr( "aria-expanded", "true" )
+			.position( position );
+	},
+
+	collapseAll: function( event, all ) {
+		clearTimeout( this.timer );
+		this.timer = this._delay(function() {
+			// If we were passed an event, look for the submenu that contains the event
+			var currentMenu = all ? this.element :
+				$( event && event.target ).closest( this.element.find( ".ui-menu" ) );
+
+			// If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
+			if ( !currentMenu.length ) {
+				currentMenu = this.element;
+			}
+
+			this._close( currentMenu );
+
+			this.blur( event );
+			this.activeMenu = currentMenu;
+		}, this.delay );
+	},
+
+	// With no arguments, closes the currently active menu - if nothing is active
+	// it closes all menus.  If passed an argument, it will search for menus BELOW
+	_close: function( startMenu ) {
+		if ( !startMenu ) {
+			startMenu = this.active ? this.active.parent() : this.element;
+		}
+
+		startMenu
+			.find( ".ui-menu" )
+				.hide()
+				.attr( "aria-hidden", "true" )
+				.attr( "aria-expanded", "false" )
+			.end()
+			.find( ".ui-state-active" ).not( ".ui-state-focus" )
+				.removeClass( "ui-state-active" );
+	},
+
+	_closeOnDocumentClick: function( event ) {
+		return !$( event.target ).closest( ".ui-menu" ).length;
+	},
+
+	_isDivider: function( item ) {
+
+		// Match hyphen, em dash, en dash
+		return !/[^\-\u2014\u2013\s]/.test( item.text() );
+	},
+
+	collapse: function( event ) {
+		var newItem = this.active &&
+			this.active.parent().closest( ".ui-menu-item", this.element );
+		if ( newItem && newItem.length ) {
+			this._close();
+			this.focus( event, newItem );
+		}
+	},
+
+	expand: function( event ) {
+		var newItem = this.active &&
+			this.active
+				.children( ".ui-menu " )
+				.find( this.options.items )
+				.first();
+
+		if ( newItem && newItem.length ) {
+			this._open( newItem.parent() );
+
+			// Delay so Firefox will not hide activedescendant change in expanding submenu from AT
+			this._delay(function() {
+				this.focus( event, newItem );
+			});
+		}
+	},
+
+	next: function( event ) {
+		this._move( "next", "first", event );
+	},
+
+	previous: function( event ) {
+		this._move( "prev", "last", event );
+	},
+
+	isFirstItem: function() {
+		return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
+	},
+
+	isLastItem: function() {
+		return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
+	},
+
+	_move: function( direction, filter, event ) {
+		var next;
+		if ( this.active ) {
+			if ( direction === "first" || direction === "last" ) {
+				next = this.active
+					[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
+					.eq( -1 );
+			} else {
+				next = this.active
+					[ direction + "All" ]( ".ui-menu-item" )
+					.eq( 0 );
+			}
+		}
+		if ( !next || !next.length || !this.active ) {
+			next = this.activeMenu.find( this.options.items )[ filter ]();
+		}
+
+		this.focus( event, next );
+	},
+
+	nextPage: function( event ) {
+		var item, base, height;
+
+		if ( !this.active ) {
+			this.next( event );
+			return;
+		}
+		if ( this.isLastItem() ) {
+			return;
+		}
+		if ( this._hasScroll() ) {
+			base = this.active.offset().top;
+			height = this.element.height();
+			this.active.nextAll( ".ui-menu-item" ).each(function() {
+				item = $( this );
+				return item.offset().top - base - height < 0;
+			});
+
+			this.focus( event, item );
+		} else {
+			this.focus( event, this.activeMenu.find( this.options.items )
+				[ !this.active ? "first" : "last" ]() );
+		}
+	},
+
+	previousPage: function( event ) {
+		var item, base, height;
+		if ( !this.active ) {
+			this.next( event );
+			return;
+		}
+		if ( this.isFirstItem() ) {
+			return;
+		}
+		if ( this._hasScroll() ) {
+			base = this.active.offset().top;
+			height = this.element.height();
+			this.active.prevAll( ".ui-menu-item" ).each(function() {
+				item = $( this );
+				return item.offset().top - base + height > 0;
+			});
+
+			this.focus( event, item );
+		} else {
+			this.focus( event, this.activeMenu.find( this.options.items ).first() );
+		}
+	},
+
+	_hasScroll: function() {
+		return this.element.outerHeight() < this.element.prop( "scrollHeight" );
+	},
+
+	select: function( event ) {
+		// TODO: It should never be possible to not have an active item at this
+		// point, but the tests don't trigger mouseenter before click.
+		this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
+		var ui = { item: this.active };
+		if ( !this.active.has( ".ui-menu" ).length ) {
+			this.collapseAll( event, true );
+		}
+		this._trigger( "select", event, ui );
+	},
+
+	_filterMenuItems: function(character) {
+		var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
+			regex = new RegExp( "^" + escapedCharacter, "i" );
+
+		return this.activeMenu
+			.find( this.options.items )
+
+			// Only match on items, not dividers or other content (#10571)
+			.filter( ".ui-menu-item" )
+			.filter(function() {
+				return regex.test( $.trim( $( this ).text() ) );
+			});
+	}
+});
+
+
+/*!
+ * jQuery UI Autocomplete 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/autocomplete/
+ */
+
+
+$.widget( "ui.autocomplete", {
+	version: "1.11.4",
+	defaultElement: "<input>",
+	options: {
+		appendTo: null,
+		autoFocus: false,
+		delay: 300,
+		minLength: 1,
+		position: {
+			my: "left top",
+			at: "left bottom",
+			collision: "none"
+		},
+		source: null,
+
+		// callbacks
+		change: null,
+		close: null,
+		focus: null,
+		open: null,
+		response: null,
+		search: null,
+		select: null
+	},
+
+	requestIndex: 0,
+	pending: 0,
+
+	_create: function() {
+		// Some browsers only repeat keydown events, not keypress events,
+		// so we use the suppressKeyPress flag to determine if we've already
+		// handled the keydown event. #7269
+		// Unfortunately the code for & in keypress is the same as the up arrow,
+		// so we use the suppressKeyPressRepeat flag to avoid handling keypress
+		// events when we know the keydown event was used to modify the
+		// search term. #7799
+		var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
+			nodeName = this.element[ 0 ].nodeName.toLowerCase(),
+			isTextarea = nodeName === "textarea",
+			isInput = nodeName === "input";
+
+		this.isMultiLine =
+			// Textareas are always multi-line
+			isTextarea ? true :
+			// Inputs are always single-line, even if inside a contentEditable element
+			// IE also treats inputs as contentEditable
+			isInput ? false :
+			// All other element types are determined by whether or not they're contentEditable
+			this.element.prop( "isContentEditable" );
+
+		this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
+		this.isNewMenu = true;
+
+		this.element
+			.addClass( "ui-autocomplete-input" )
+			.attr( "autocomplete", "off" );
+
+		this._on( this.element, {
+			keydown: function( event ) {
+				if ( this.element.prop( "readOnly" ) ) {
+					suppressKeyPress = true;
+					suppressInput = true;
+					suppressKeyPressRepeat = true;
+					return;
+				}
+
+				suppressKeyPress = false;
+				suppressInput = false;
+				suppressKeyPressRepeat = false;
+				var keyCode = $.ui.keyCode;
+				switch ( event.keyCode ) {
+				case keyCode.PAGE_UP:
+					suppressKeyPress = true;
+					this._move( "previousPage", event );
+					break;
+				case keyCode.PAGE_DOWN:
+					suppressKeyPress = true;
+					this._move( "nextPage", event );
+					break;
+				case keyCode.UP:
+					suppressKeyPress = true;
+					this._keyEvent( "previous", event );
+					break;
+				case keyCode.DOWN:
+					suppressKeyPress = true;
+					this._keyEvent( "next", event );
+					break;
+				case keyCode.ENTER:
+					// when menu is open and has focus
+					if ( this.menu.active ) {
+						// #6055 - Opera still allows the keypress to occur
+						// which causes forms to submit
+						suppressKeyPress = true;
+						event.preventDefault();
+						this.menu.select( event );
+					}
+					break;
+				case keyCode.TAB:
+					if ( this.menu.active ) {
+						this.menu.select( event );
+					}
+					break;
+				case keyCode.ESCAPE:
+					if ( this.menu.element.is( ":visible" ) ) {
+						if ( !this.isMultiLine ) {
+							this._value( this.term );
+						}
+						this.close( event );
+						// Different browsers have different default behavior for escape
+						// Single press can mean undo or clear
+						// Double press in IE means clear the whole form
+						event.preventDefault();
+					}
+					break;
+				default:
+					suppressKeyPressRepeat = true;
+					// search timeout should be triggered before the input value is changed
+					this._searchTimeout( event );
+					break;
+				}
+			},
+			keypress: function( event ) {
+				if ( suppressKeyPress ) {
+					suppressKeyPress = false;
+					if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
+						event.preventDefault();
+					}
+					return;
+				}
+				if ( suppressKeyPressRepeat ) {
+					return;
+				}
+
+				// replicate some key handlers to allow them to repeat in Firefox and Opera
+				var keyCode = $.ui.keyCode;
+				switch ( event.keyCode ) {
+				case keyCode.PAGE_UP:
+					this._move( "previousPage", event );
+					break;
+				case keyCode.PAGE_DOWN:
+					this._move( "nextPage", event );
+					break;
+				case keyCode.UP:
+					this._keyEvent( "previous", event );
+					break;
+				case keyCode.DOWN:
+					this._keyEvent( "next", event );
+					break;
+				}
+			},
+			input: function( event ) {
+				if ( suppressInput ) {
+					suppressInput = false;
+					event.preventDefault();
+					return;
+				}
+				this._searchTimeout( event );
+			},
+			focus: function() {
+				this.selectedItem = null;
+				this.previous = this._value();
+			},
+			blur: function( event ) {
+				if ( this.cancelBlur ) {
+					delete this.cancelBlur;
+					return;
+				}
+
+				clearTimeout( this.searching );
+				this.close( event );
+				this._change( event );
+			}
+		});
+
+		this._initSource();
+		this.menu = $( "<ul>" )
+			.addClass( "ui-autocomplete ui-front" )
+			.appendTo( this._appendTo() )
+			.menu({
+				// disable ARIA support, the live region takes care of that
+				role: null
+			})
+			.hide()
+			.menu( "instance" );
+
+		this._on( this.menu.element, {
+			mousedown: function( event ) {
+				// prevent moving focus out of the text field
+				event.preventDefault();
+
+				// IE doesn't prevent moving focus even with event.preventDefault()
+				// so we set a flag to know when we should ignore the blur event
+				this.cancelBlur = true;
+				this._delay(function() {
+					delete this.cancelBlur;
+				});
+
+				// clicking on the scrollbar causes focus to shift to the body
+				// but we can't detect a mouseup or a click immediately afterward
+				// so we have to track the next mousedown and close the menu if
+				// the user clicks somewhere outside of the autocomplete
+				var menuElement = this.menu.element[ 0 ];
+				if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
+					this._delay(function() {
+						var that = this;
+						this.document.one( "mousedown", function( event ) {
+							if ( event.target !== that.element[ 0 ] &&
+									event.target !== menuElement &&
+									!$.contains( menuElement, event.target ) ) {
+								that.close();
+							}
+						});
+					});
+				}
+			},
+			menufocus: function( event, ui ) {
+				var label, item;
+				// support: Firefox
+				// Prevent accidental activation of menu items in Firefox (#7024 #9118)
+				if ( this.isNewMenu ) {
+					this.isNewMenu = false;
+					if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
+						this.menu.blur();
+
+						this.document.one( "mousemove", function() {
+							$( event.target ).trigger( event.originalEvent );
+						});
+
+						return;
+					}
+				}
+
+				item = ui.item.data( "ui-autocomplete-item" );
+				if ( false !== this._trigger( "focus", event, { item: item } ) ) {
+					// use value to match what will end up in the input, if it was a key event
+					if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
+						this._value( item.value );
+					}
+				}
+
+				// Announce the value in the liveRegion
+				label = ui.item.attr( "aria-label" ) || item.value;
+				if ( label && $.trim( label ).length ) {
+					this.liveRegion.children().hide();
+					$( "<div>" ).text( label ).appendTo( this.liveRegion );
+				}
+			},
+			menuselect: function( event, ui ) {
+				var item = ui.item.data( "ui-autocomplete-item" ),
+					previous = this.previous;
+
+				// only trigger when focus was lost (click on menu)
+				if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) {
+					this.element.focus();
+					this.previous = previous;
+					// #6109 - IE triggers two focus events and the second
+					// is asynchronous, so we need to reset the previous
+					// term synchronously and asynchronously :-(
+					this._delay(function() {
+						this.previous = previous;
+						this.selectedItem = item;
+					});
+				}
+
+				if ( false !== this._trigger( "select", event, { item: item } ) ) {
+					this._value( item.value );
+				}
+				// reset the term after the select event
+				// this allows custom select handling to work properly
+				this.term = this._value();
+
+				this.close( event );
+				this.selectedItem = item;
+			}
+		});
+
+		this.liveRegion = $( "<span>", {
+				role: "status",
+				"aria-live": "assertive",
+				"aria-relevant": "additions"
+			})
+			.addClass( "ui-helper-hidden-accessible" )
+			.appendTo( this.document[ 0 ].body );
+
+		// turning off autocomplete prevents the browser from remembering the
+		// value when navigating through history, so we re-enable autocomplete
+		// if the page is unloaded before the widget is destroyed. #7790
+		this._on( this.window, {
+			beforeunload: function() {
+				this.element.removeAttr( "autocomplete" );
+			}
+		});
+	},
+
+	_destroy: function() {
+		clearTimeout( this.searching );
+		this.element
+			.removeClass( "ui-autocomplete-input" )
+			.removeAttr( "autocomplete" );
+		this.menu.element.remove();
+		this.liveRegion.remove();
+	},
+
+	_setOption: function( key, value ) {
+		this._super( key, value );
+		if ( key === "source" ) {
+			this._initSource();
+		}
+		if ( key === "appendTo" ) {
+			this.menu.element.appendTo( this._appendTo() );
+		}
+		if ( key === "disabled" && value && this.xhr ) {
+			this.xhr.abort();
+		}
+	},
+
+	_appendTo: function() {
+		var element = this.options.appendTo;
+
+		if ( element ) {
+			element = element.jquery || element.nodeType ?
+				$( element ) :
+				this.document.find( element ).eq( 0 );
+		}
+
+		if ( !element || !element[ 0 ] ) {
+			element = this.element.closest( ".ui-front" );
+		}
+
+		if ( !element.length ) {
+			element = this.document[ 0 ].body;
+		}
+
+		return element;
+	},
+
+	_initSource: function() {
+		var array, url,
+			that = this;
+		if ( $.isArray( this.options.source ) ) {
+			array = this.options.source;
+			this.source = function( request, response ) {
+				response( $.ui.autocomplete.filter( array, request.term ) );
+			};
+		} else if ( typeof this.options.source === "string" ) {
+			url = this.options.source;
+			this.source = function( request, response ) {
+				if ( that.xhr ) {
+					that.xhr.abort();
+				}
+				that.xhr = $.ajax({
+					url: url,
+					data: request,
+					dataType: "json",
+					success: function( data ) {
+						response( data );
+					},
+					error: function() {
+						response([]);
+					}
+				});
+			};
+		} else {
+			this.source = this.options.source;
+		}
+	},
+
+	_searchTimeout: function( event ) {
+		clearTimeout( this.searching );
+		this.searching = this._delay(function() {
+
+			// Search if the value has changed, or if the user retypes the same value (see #7434)
+			var equalValues = this.term === this._value(),
+				menuVisible = this.menu.element.is( ":visible" ),
+				modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
+
+			if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
+				this.selectedItem = null;
+				this.search( null, event );
+			}
+		}, this.options.delay );
+	},
+
+	search: function( value, event ) {
+		value = value != null ? value : this._value();
+
+		// always save the actual value, not the one passed as an argument
+		this.term = this._value();
+
+		if ( value.length < this.options.minLength ) {
+			return this.close( event );
+		}
+
+		if ( this._trigger( "search", event ) === false ) {
+			return;
+		}
+
+		return this._search( value );
+	},
+
+	_search: function( value ) {
+		this.pending++;
+		this.element.addClass( "ui-autocomplete-loading" );
+		this.cancelSearch = false;
+
+		this.source( { term: value }, this._response() );
+	},
+
+	_response: function() {
+		var index = ++this.requestIndex;
+
+		return $.proxy(function( content ) {
+			if ( index === this.requestIndex ) {
+				this.__response( content );
+			}
+
+			this.pending--;
+			if ( !this.pending ) {
+				this.element.removeClass( "ui-autocomplete-loading" );
+			}
+		}, this );
+	},
+
+	__response: function( content ) {
+		if ( content ) {
+			content = this._normalize( content );
+		}
+		this._trigger( "response", null, { content: content } );
+		if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
+			this._suggest( content );
+			this._trigger( "open" );
+		} else {
+			// use ._close() instead of .close() so we don't cancel future searches
+			this._close();
+		}
+	},
+
+	close: function( event ) {
+		this.cancelSearch = true;
+		this._close( event );
+	},
+
+	_close: function( event ) {
+		if ( this.menu.element.is( ":visible" ) ) {
+			this.menu.element.hide();
+			this.menu.blur();
+			this.isNewMenu = true;
+			this._trigger( "close", event );
+		}
+	},
+
+	_change: function( event ) {
+		if ( this.previous !== this._value() ) {
+			this._trigger( "change", event, { item: this.selectedItem } );
+		}
+	},
+
+	_normalize: function( items ) {
+		// assume all items have the right format when the first item is complete
+		if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
+			return items;
+		}
+		return $.map( items, function( item ) {
+			if ( typeof item === "string" ) {
+				return {
+					label: item,
+					value: item
+				};
+			}
+			return $.extend( {}, item, {
+				label: item.label || item.value,
+				value: item.value || item.label
+			});
+		});
+	},
+
+	_suggest: function( items ) {
+		var ul = this.menu.element.empty();
+		this._renderMenu( ul, items );
+		this.isNewMenu = true;
+		this.menu.refresh();
+
+		// size and position menu
+		ul.show();
+		this._resizeMenu();
+		ul.position( $.extend({
+			of: this.element
+		}, this.options.position ) );
+
+		if ( this.options.autoFocus ) {
+			this.menu.next();
+		}
+	},
+
+	_resizeMenu: function() {
+		var ul = this.menu.element;
+		ul.outerWidth( Math.max(
+			// Firefox wraps long text (possibly a rounding bug)
+			// so we add 1px to avoid the wrapping (#7513)
+			ul.width( "" ).outerWidth() + 1,
+			this.element.outerWidth()
+		) );
+	},
+
+	_renderMenu: function( ul, items ) {
+		var that = this;
+		$.each( items, function( index, item ) {
+			that._renderItemData( ul, item );
+		});
+	},
+
+	_renderItemData: function( ul, item ) {
+		return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
+	},
+
+	_renderItem: function( ul, item ) {
+		return $( "<li>" ).text( item.label ).appendTo( ul );
+	},
+
+	_move: function( direction, event ) {
+		if ( !this.menu.element.is( ":visible" ) ) {
+			this.search( null, event );
+			return;
+		}
+		if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
+				this.menu.isLastItem() && /^next/.test( direction ) ) {
+
+			if ( !this.isMultiLine ) {
+				this._value( this.term );
+			}
+
+			this.menu.blur();
+			return;
+		}
+		this.menu[ direction ]( event );
+	},
+
+	widget: function() {
+		return this.menu.element;
+	},
+
+	_value: function() {
+		return this.valueMethod.apply( this.element, arguments );
+	},
+
+	_keyEvent: function( keyEvent, event ) {
+		if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
+			this._move( keyEvent, event );
+
+			// prevents moving cursor to beginning/end of the text field in some browsers
+			event.preventDefault();
+		}
+	}
+});
+
+$.extend( $.ui.autocomplete, {
+	escapeRegex: function( value ) {
+		return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
+	},
+	filter: function( array, term ) {
+		var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
+		return $.grep( array, function( value ) {
+			return matcher.test( value.label || value.value || value );
+		});
+	}
+});
+
+// live region extension, adding a `messages` option
+// NOTE: This is an experimental API. We are still investigating
+// a full solution for string manipulation and internationalization.
+$.widget( "ui.autocomplete", $.ui.autocomplete, {
+	options: {
+		messages: {
+			noResults: "No search results.",
+			results: function( amount ) {
+				return amount + ( amount > 1 ? " results are" : " result is" ) +
+					" available, use up and down arrow keys to navigate.";
+			}
+		}
+	},
+
+	__response: function( content ) {
+		var message;
+		this._superApply( arguments );
+		if ( this.options.disabled || this.cancelSearch ) {
+			return;
+		}
+		if ( content && content.length ) {
+			message = this.options.messages.results( content.length );
+		} else {
+			message = this.options.messages.noResults;
+		}
+		this.liveRegion.children().hide();
+		$( "<div>" ).text( message ).appendTo( this.liveRegion );
+	}
+});
+
+var autocomplete = $.ui.autocomplete;
+
+
+/*!
+ * jQuery UI Button 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/button/
+ */
+
+
+var lastActive,
+	baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
+	typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
+	formResetHandler = function() {
+		var form = $( this );
+		setTimeout(function() {
+			form.find( ":ui-button" ).button( "refresh" );
+		}, 1 );
+	},
+	radioGroup = function( radio ) {
+		var name = radio.name,
+			form = radio.form,
+			radios = $( [] );
+		if ( name ) {
+			name = name.replace( /'/g, "\\'" );
+			if ( form ) {
+				radios = $( form ).find( "[name='" + name + "'][type=radio]" );
+			} else {
+				radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument )
+					.filter(function() {
+						return !this.form;
+					});
+			}
+		}
+		return radios;
+	};
+
+$.widget( "ui.button", {
+	version: "1.11.4",
+	defaultElement: "<button>",
+	options: {
+		disabled: null,
+		text: true,
+		label: null,
+		icons: {
+			primary: null,
+			secondary: null
+		}
+	},
+	_create: function() {
+		this.element.closest( "form" )
+			.unbind( "reset" + this.eventNamespace )
+			.bind( "reset" + this.eventNamespace, formResetHandler );
+
+		if ( typeof this.options.disabled !== "boolean" ) {
+			this.options.disabled = !!this.element.prop( "disabled" );
+		} else {
+			this.element.prop( "disabled", this.options.disabled );
+		}
+
+		this._determineButtonType();
+		this.hasTitle = !!this.buttonElement.attr( "title" );
+
+		var that = this,
+			options = this.options,
+			toggleButton = this.type === "checkbox" || this.type === "radio",
+			activeClass = !toggleButton ? "ui-state-active" : "";
+
+		if ( options.label === null ) {
+			options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
+		}
+
+		this._hoverable( this.buttonElement );
+
+		this.buttonElement
+			.addClass( baseClasses )
+			.attr( "role", "button" )
+			.bind( "mouseenter" + this.eventNamespace, function() {
+				if ( options.disabled ) {
+					return;
+				}
+				if ( this === lastActive ) {
+					$( this ).addClass( "ui-state-active" );
+				}
+			})
+			.bind( "mouseleave" + this.eventNamespace, function() {
+				if ( options.disabled ) {
+					return;
+				}
+				$( this ).removeClass( activeClass );
+			})
+			.bind( "click" + this.eventNamespace, function( event ) {
+				if ( options.disabled ) {
+					event.preventDefault();
+					event.stopImmediatePropagation();
+				}
+			});
+
+		// Can't use _focusable() because the element that receives focus
+		// and the element that gets the ui-state-focus class are different
+		this._on({
+			focus: function() {
+				this.buttonElement.addClass( "ui-state-focus" );
+			},
+			blur: function() {
+				this.buttonElement.removeClass( "ui-state-focus" );
+			}
+		});
+
+		if ( toggleButton ) {
+			this.element.bind( "change" + this.eventNamespace, function() {
+				that.refresh();
+			});
+		}
+
+		if ( this.type === "checkbox" ) {
+			this.buttonElement.bind( "click" + this.eventNamespace, function() {
+				if ( options.disabled ) {
+					return false;
+				}
+			});
+		} else if ( this.type === "radio" ) {
+			this.buttonElement.bind( "click" + this.eventNamespace, function() {
+				if ( options.disabled ) {
+					return false;
+				}
+				$( this ).addClass( "ui-state-active" );
+				that.buttonElement.attr( "aria-pressed", "true" );
+
+				var radio = that.element[ 0 ];
+				radioGroup( radio )
+					.not( radio )
+					.map(function() {
+						return $( this ).button( "widget" )[ 0 ];
+					})
+					.removeClass( "ui-state-active" )
+					.attr( "aria-pressed", "false" );
+			});
+		} else {
+			this.buttonElement
+				.bind( "mousedown" + this.eventNamespace, function() {
+					if ( options.disabled ) {
+						return false;
+					}
+					$( this ).addClass( "ui-state-active" );
+					lastActive = this;
+					that.document.one( "mouseup", function() {
+						lastActive = null;
+					});
+				})
+				.bind( "mouseup" + this.eventNamespace, function() {
+					if ( options.disabled ) {
+						return false;
+					}
+					$( this ).removeClass( "ui-state-active" );
+				})
+				.bind( "keydown" + this.eventNamespace, function(event) {
+					if ( options.disabled ) {
+						return false;
+					}
+					if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
+						$( this ).addClass( "ui-state-active" );
+					}
+				})
+				// see #8559, we bind to blur here in case the button element loses
+				// focus between keydown and keyup, it would be left in an "active" state
+				.bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
+					$( this ).removeClass( "ui-state-active" );
+				});
+
+			if ( this.buttonElement.is("a") ) {
+				this.buttonElement.keyup(function(event) {
+					if ( event.keyCode === $.ui.keyCode.SPACE ) {
+						// TODO pass through original event correctly (just as 2nd argument doesn't work)
+						$( this ).click();
+					}
+				});
+			}
+		}
+
+		this._setOption( "disabled", options.disabled );
+		this._resetButton();
+	},
+
+	_determineButtonType: function() {
+		var ancestor, labelSelector, checked;
+
+		if ( this.element.is("[type=checkbox]") ) {
+			this.type = "checkbox";
+		} else if ( this.element.is("[type=radio]") ) {
+			this.type = "radio";
+		} else if ( this.element.is("input") ) {
+			this.type = "input";
+		} else {
+			this.type = "button";
+		}
+
+		if ( this.type === "checkbox" || this.type === "radio" ) {
+			// we don't search against the document in case the element
+			// is disconnected from the DOM
+			ancestor = this.element.parents().last();
+			labelSelector = "label[for='" + this.element.attr("id") + "']";
+			this.buttonElement = ancestor.find( labelSelector );
+			if ( !this.buttonElement.length ) {
+				ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
+				this.buttonElement = ancestor.filter( labelSelector );
+				if ( !this.buttonElement.length ) {
+					this.buttonElement = ancestor.find( labelSelector );
+				}
+			}
+			this.element.addClass( "ui-helper-hidden-accessible" );
+
+			checked = this.element.is( ":checked" );
+			if ( checked ) {
+				this.buttonElement.addClass( "ui-state-active" );
+			}
+			this.buttonElement.prop( "aria-pressed", checked );
+		} else {
+			this.buttonElement = this.element;
+		}
+	},
+
+	widget: function() {
+		return this.buttonElement;
+	},
+
+	_destroy: function() {
+		this.element
+			.removeClass( "ui-helper-hidden-accessible" );
+		this.buttonElement
+			.removeClass( baseClasses + " ui-state-active " + typeClasses )
+			.removeAttr( "role" )
+			.removeAttr( "aria-pressed" )
+			.html( this.buttonElement.find(".ui-button-text").html() );
+
+		if ( !this.hasTitle ) {
+			this.buttonElement.removeAttr( "title" );
+		}
+	},
+
+	_setOption: function( key, value ) {
+		this._super( key, value );
+		if ( key === "disabled" ) {
+			this.widget().toggleClass( "ui-state-disabled", !!value );
+			this.element.prop( "disabled", !!value );
+			if ( value ) {
+				if ( this.type === "checkbox" || this.type === "radio" ) {
+					this.buttonElement.removeClass( "ui-state-focus" );
+				} else {
+					this.buttonElement.removeClass( "ui-state-focus ui-state-active" );
+				}
+			}
+			return;
+		}
+		this._resetButton();
+	},
+
+	refresh: function() {
+		//See #8237 & #8828
+		var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
+
+		if ( isDisabled !== this.options.disabled ) {
+			this._setOption( "disabled", isDisabled );
+		}
+		if ( this.type === "radio" ) {
+			radioGroup( this.element[0] ).each(function() {
+				if ( $( this ).is( ":checked" ) ) {
+					$( this ).button( "widget" )
+						.addClass( "ui-state-active" )
+						.attr( "aria-pressed", "true" );
+				} else {
+					$( this ).button( "widget" )
+						.removeClass( "ui-state-active" )
+						.attr( "aria-pressed", "false" );
+				}
+			});
+		} else if ( this.type === "checkbox" ) {
+			if ( this.element.is( ":checked" ) ) {
+				this.buttonElement
+					.addClass( "ui-state-active" )
+					.attr( "aria-pressed", "true" );
+			} else {
+				this.buttonElement
+					.removeClass( "ui-state-active" )
+					.attr( "aria-pressed", "false" );
+			}
+		}
+	},
+
+	_resetButton: function() {
+		if ( this.type === "input" ) {
+			if ( this.options.label ) {
+				this.element.val( this.options.label );
+			}
+			return;
+		}
+		var buttonElement = this.buttonElement.removeClass( typeClasses ),
+			buttonText = $( "<span></span>", this.document[0] )
+				.addClass( "ui-button-text" )
+				.html( this.options.label )
+				.appendTo( buttonElement.empty() )
+				.text(),
+			icons = this.options.icons,
+			multipleIcons = icons.primary && icons.secondary,
+			buttonClasses = [];
+
+		if ( icons.primary || icons.secondary ) {
+			if ( this.options.text ) {
+				buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
+			}
+
+			if ( icons.primary ) {
+				buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
+			}
+
+			if ( icons.secondary ) {
+				buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
+			}
+
+			if ( !this.options.text ) {
+				buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
+
+				if ( !this.hasTitle ) {
+					buttonElement.attr( "title", $.trim( buttonText ) );
+				}
+			}
+		} else {
+			buttonClasses.push( "ui-button-text-only" );
+		}
+		buttonElement.addClass( buttonClasses.join( " " ) );
+	}
+});
+
+$.widget( "ui.buttonset", {
+	version: "1.11.4",
+	options: {
+		items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
+	},
+
+	_create: function() {
+		this.element.addClass( "ui-buttonset" );
+	},
+
+	_init: function() {
+		this.refresh();
+	},
+
+	_setOption: function( key, value ) {
+		if ( key === "disabled" ) {
+			this.buttons.button( "option", key, value );
+		}
+
+		this._super( key, value );
+	},
+
+	refresh: function() {
+		var rtl = this.element.css( "direction" ) === "rtl",
+			allButtons = this.element.find( this.options.items ),
+			existingButtons = allButtons.filter( ":ui-button" );
+
+		// Initialize new buttons
+		allButtons.not( ":ui-button" ).button();
+
+		// Refresh existing buttons
+		existingButtons.button( "refresh" );
+
+		this.buttons = allButtons
+			.map(function() {
+				return $( this ).button( "widget" )[ 0 ];
+			})
+				.removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
+				.filter( ":first" )
+					.addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
+				.end()
+				.filter( ":last" )
+					.addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
+				.end()
+			.end();
+	},
+
+	_destroy: function() {
+		this.element.removeClass( "ui-buttonset" );
+		this.buttons
+			.map(function() {
+				return $( this ).button( "widget" )[ 0 ];
+			})
+				.removeClass( "ui-corner-left ui-corner-right" )
+			.end()
+			.button( "destroy" );
+	}
+});
+
+var button = $.ui.button;
+
+
+/*!
+ * jQuery UI Datepicker 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/datepicker/
+ */
+
+
+$.extend($.ui, { datepicker: { version: "1.11.4" } });
+
+var datepicker_instActive;
+
+function datepicker_getZindex( elem ) {
+	var position, value;
+	while ( elem.length && elem[ 0 ] !== document ) {
+		// Ignore z-index if position is set to a value where z-index is ignored by the browser
+		// This makes behavior of this function consistent across browsers
+		// WebKit always returns auto if the element is positioned
+		position = elem.css( "position" );
+		if ( position === "absolute" || position === "relative" || position === "fixed" ) {
+			// IE returns 0 when zIndex is not specified
+			// other browsers return a string
+			// we ignore the case of nested elements with an explicit value of 0
+			// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
+			value = parseInt( elem.css( "zIndex" ), 10 );
+			if ( !isNaN( value ) && value !== 0 ) {
+				return value;
+			}
+		}
+		elem = elem.parent();
+	}
+
+	return 0;
+}
+/* Date picker manager.
+   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
+   Settings for (groups of) date pickers are maintained in an instance object,
+   allowing multiple different settings on the same page. */
+
+function Datepicker() {
+	this._curInst = null; // The current instance in use
+	this._keyEvent = false; // If the last event was a key event
+	this._disabledInputs = []; // List of date picker inputs that have been disabled
+	this._datepickerShowing = false; // True if the popup picker is showing , false if not
+	this._inDialog = false; // True if showing within a "dialog", false if not
+	this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
+	this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
+	this._appendClass = "ui-datepicker-append"; // The name of the append marker class
+	this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
+	this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
+	this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
+	this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
+	this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
+	this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
+	this.regional = []; // Available regional settings, indexed by language code
+	this.regional[""] = { // Default regional settings
+		closeText: "Done", // Display text for close link
+		prevText: "Prev", // Display text for previous month link
+		nextText: "Next", // Display text for next month link
+		currentText: "Today", // Display text for current month link
+		monthNames: ["January","February","March","April","May","June",
+			"July","August","September","October","November","December"], // Names of months for drop-down and formatting
+		monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
+		dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
+		dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
+		dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
+		weekHeader: "Wk", // Column header for week of the year
+		dateFormat: "mm/dd/yy", // See format options on parseDate
+		firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
+		isRTL: false, // True if right-to-left language, false if left-to-right
+		showMonthAfterYear: false, // True if the year select precedes month, false for month then year
+		yearSuffix: "" // Additional text to append to the year in the month headers
+	};
+	this._defaults = { // Global defaults for all the date picker instances
+		showOn: "focus", // "focus" for popup on focus,
+			// "button" for trigger button, or "both" for either
+		showAnim: "fadeIn", // Name of jQuery animation for popup
+		showOptions: {}, // Options for enhanced animations
+		defaultDate: null, // Used when field is blank: actual date,
+			// +/-number for offset from today, null for today
+		appendText: "", // Display text following the input box, e.g. showing the format
+		buttonText: "...", // Text for trigger button
+		buttonImage: "", // URL for trigger button image
+		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
+		hideIfNoPrevNext: false, // True to hide next/previous month links
+			// if not applicable, false to just disable them
+		navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
+		gotoCurrent: false, // True if today link goes back to current selection instead
+		changeMonth: false, // True if month can be selected directly, false if only prev/next
+		changeYear: false, // True if year can be selected directly, false if only prev/next
+		yearRange: "c-10:c+10", // Range of years to display in drop-down,
+			// either relative to today's year (-nn:+nn), relative to currently displayed year
+			// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
+		showOtherMonths: false, // True to show dates in other months, false to leave blank
+		selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
+		showWeek: false, // True to show week of the year, false to not show it
+		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
+			// takes a Date and returns the number of the week for it
+		shortYearCutoff: "+10", // Short year values < this are in the current century,
+			// > this are in the previous century,
+			// string value starting with "+" for current year + value
+		minDate: null, // The earliest selectable date, or null for no limit
+		maxDate: null, // The latest selectable date, or null for no limit
+		duration: "fast", // Duration of display/closure
+		beforeShowDay: null, // Function that takes a date and returns an array with
+			// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
+			// [2] = cell title (optional), e.g. $.datepicker.noWeekends
+		beforeShow: null, // Function that takes an input field and
+			// returns a set of custom settings for the date picker
+		onSelect: null, // Define a callback function when a date is selected
+		onChangeMonthYear: null, // Define a callback function when the month or year is changed
+		onClose: null, // Define a callback function when the datepicker is closed
+		numberOfMonths: 1, // Number of months to show at a time
+		showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
+		stepMonths: 1, // Number of months to step back/forward
+		stepBigMonths: 12, // Number of months to step back/forward for the big links
+		altField: "", // Selector for an alternate field to store selected dates into
+		altFormat: "", // The date format to use for the alternate field
+		constrainInput: true, // The input is constrained by the current date format
+		showButtonPanel: false, // True to show button panel, false to not show it
+		autoSize: false, // True to size the input for the date format, false to leave as is
+		disabled: false // The initial disabled state
+	};
+	$.extend(this._defaults, this.regional[""]);
+	this.regional.en = $.extend( true, {}, this.regional[ "" ]);
+	this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
+	this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
+}
+
+$.extend(Datepicker.prototype, {
+	/* Class name added to elements to indicate already configured with a date picker. */
+	markerClassName: "hasDatepicker",
+
+	//Keep track of the maximum number of rows displayed (see #7043)
+	maxRows: 4,
+
+	// TODO rename to "widget" when switching to widget factory
+	_widgetDatepicker: function() {
+		return this.dpDiv;
+	},
+
+	/* Override the default settings for all instances of the date picker.
+	 * @param  settings  object - the new settings to use as defaults (anonymous object)
+	 * @return the manager object
+	 */
+	setDefaults: function(settings) {
+		datepicker_extendRemove(this._defaults, settings || {});
+		return this;
+	},
+
+	/* Attach the date picker to a jQuery selection.
+	 * @param  target	element - the target input field or division or span
+	 * @param  settings  object - the new settings to use for this date picker instance (anonymous)
+	 */
+	_attachDatepicker: function(target, settings) {
+		var nodeName, inline, inst;
+		nodeName = target.nodeName.toLowerCase();
+		inline = (nodeName === "div" || nodeName === "span");
+		if (!target.id) {
+			this.uuid += 1;
+			target.id = "dp" + this.uuid;
+		}
+		inst = this._newInst($(target), inline);
+		inst.settings = $.extend({}, settings || {});
+		if (nodeName === "input") {
+			this._connectDatepicker(target, inst);
+		} else if (inline) {
+			this._inlineDatepicker(target, inst);
+		}
+	},
+
+	/* Create a new instance object. */
+	_newInst: function(target, inline) {
+		var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
+		return {id: id, input: target, // associated target
+			selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
+			drawMonth: 0, drawYear: 0, // month being drawn
+			inline: inline, // is datepicker inline or not
+			dpDiv: (!inline ? this.dpDiv : // presentation div
+			datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
+	},
+
+	/* Attach the date picker to an input field. */
+	_connectDatepicker: function(target, inst) {
+		var input = $(target);
+		inst.append = $([]);
+		inst.trigger = $([]);
+		if (input.hasClass(this.markerClassName)) {
+			return;
+		}
+		this._attachments(input, inst);
+		input.addClass(this.markerClassName).keydown(this._doKeyDown).
+			keypress(this._doKeyPress).keyup(this._doKeyUp);
+		this._autoSize(inst);
+		$.data(target, "datepicker", inst);
+		//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
+		if( inst.settings.disabled ) {
+			this._disableDatepicker( target );
+		}
+	},
+
+	/* Make attachments based on settings. */
+	_attachments: function(input, inst) {
+		var showOn, buttonText, buttonImage,
+			appendText = this._get(inst, "appendText"),
+			isRTL = this._get(inst, "isRTL");
+
+		if (inst.append) {
+			inst.append.remove();
+		}
+		if (appendText) {
+			inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
+			input[isRTL ? "before" : "after"](inst.append);
+		}
+
+		input.unbind("focus", this._showDatepicker);
+
+		if (inst.trigger) {
+			inst.trigger.remove();
+		}
+
+		showOn = this._get(inst, "showOn");
+		if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
+			input.focus(this._showDatepicker);
+		}
+		if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
+			buttonText = this._get(inst, "buttonText");
+			buttonImage = this._get(inst, "buttonImage");
+			inst.trigger = $(this._get(inst, "buttonImageOnly") ?
+				$("<img/>").addClass(this._triggerClass).
+					attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
+				$("<button type='button'></button>").addClass(this._triggerClass).
+					html(!buttonImage ? buttonText : $("<img/>").attr(
+					{ src:buttonImage, alt:buttonText, title:buttonText })));
+			input[isRTL ? "before" : "after"](inst.trigger);
+			inst.trigger.click(function() {
+				if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
+					$.datepicker._hideDatepicker();
+				} else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
+					$.datepicker._hideDatepicker();
+					$.datepicker._showDatepicker(input[0]);
+				} else {
+					$.datepicker._showDatepicker(input[0]);
+				}
+				return false;
+			});
+		}
+	},
+
+	/* Apply the maximum length for the date format. */
+	_autoSize: function(inst) {
+		if (this._get(inst, "autoSize") && !inst.inline) {
+			var findMax, max, maxI, i,
+				date = new Date(2009, 12 - 1, 20), // Ensure double digits
+				dateFormat = this._get(inst, "dateFormat");
+
+			if (dateFormat.match(/[DM]/)) {
+				findMax = function(names) {
+					max = 0;
+					maxI = 0;
+					for (i = 0; i < names.length; i++) {
+						if (names[i].length > max) {
+							max = names[i].length;
+							maxI = i;
+						}
+					}
+					return maxI;
+				};
+				date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
+					"monthNames" : "monthNamesShort"))));
+				date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
+					"dayNames" : "dayNamesShort"))) + 20 - date.getDay());
+			}
+			inst.input.attr("size", this._formatDate(inst, date).length);
+		}
+	},
+
+	/* Attach an inline date picker to a div. */
+	_inlineDatepicker: function(target, inst) {
+		var divSpan = $(target);
+		if (divSpan.hasClass(this.markerClassName)) {
+			return;
+		}
+		divSpan.addClass(this.markerClassName).append(inst.dpDiv);
+		$.data(target, "datepicker", inst);
+		this._setDate(inst, this._getDefaultDate(inst), true);
+		this._updateDatepicker(inst);
+		this._updateAlternate(inst);
+		//If disabled option is true, disable the datepicker before showing it (see ticket #5665)
+		if( inst.settings.disabled ) {
+			this._disableDatepicker( target );
+		}
+		// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
+		// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
+		inst.dpDiv.css( "display", "block" );
+	},
+
+	/* Pop-up the date picker in a "dialog" box.
+	 * @param  input element - ignored
+	 * @param  date	string or Date - the initial date to display
+	 * @param  onSelect  function - the function to call when a date is selected
+	 * @param  settings  object - update the dialog date picker instance's settings (anonymous object)
+	 * @param  pos int[2] - coordinates for the dialog's position within the screen or
+	 *					event - with x/y coordinates or
+	 *					leave empty for default (screen centre)
+	 * @return the manager object
+	 */
+	_dialogDatepicker: function(input, date, onSelect, settings, pos) {
+		var id, browserWidth, browserHeight, scrollX, scrollY,
+			inst = this._dialogInst; // internal instance
+
+		if (!inst) {
+			this.uuid += 1;
+			id = "dp" + this.uuid;
+			this._dialogInput = $("<input type='text' id='" + id +
+				"' style='position: absolute; top: -100px; width: 0px;'/>");
+			this._dialogInput.keydown(this._doKeyDown);
+			$("body").append(this._dialogInput);
+			inst = this._dialogInst = this._newInst(this._dialogInput, false);
+			inst.settings = {};
+			$.data(this._dialogInput[0], "datepicker", inst);
+		}
+		datepicker_extendRemove(inst.settings, settings || {});
+		date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
+		this._dialogInput.val(date);
+
+		this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
+		if (!this._pos) {
+			browserWidth = document.documentElement.clientWidth;
+			browserHeight = document.documentElement.clientHeight;
+			scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
+			scrollY = document.documentElement.scrollTop || document.body.scrollTop;
+			this._pos = // should use actual width/height below
+				[(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
+		}
+
+		// move input on screen for focus, but hidden behind dialog
+		this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
+		inst.settings.onSelect = onSelect;
+		this._inDialog = true;
+		this.dpDiv.addClass(this._dialogClass);
+		this._showDatepicker(this._dialogInput[0]);
+		if ($.blockUI) {
+			$.blockUI(this.dpDiv);
+		}
+		$.data(this._dialogInput[0], "datepicker", inst);
+		return this;
+	},
+
+	/* Detach a datepicker from its control.
+	 * @param  target	element - the target input field or division or span
+	 */
+	_destroyDatepicker: function(target) {
+		var nodeName,
+			$target = $(target),
+			inst = $.data(target, "datepicker");
+
+		if (!$target.hasClass(this.markerClassName)) {
+			return;
+		}
+
+		nodeName = target.nodeName.toLowerCase();
+		$.removeData(target, "datepicker");
+		if (nodeName === "input") {
+			inst.append.remove();
+			inst.trigger.remove();
+			$target.removeClass(this.markerClassName).
+				unbind("focus", this._showDatepicker).
+				unbind("keydown", this._doKeyDown).
+				unbind("keypress", this._doKeyPress).
+				unbind("keyup", this._doKeyUp);
+		} else if (nodeName === "div" || nodeName === "span") {
+			$target.removeClass(this.markerClassName).empty();
+		}
+
+		if ( datepicker_instActive === inst ) {
+			datepicker_instActive = null;
+		}
+	},
+
+	/* Enable the date picker to a jQuery selection.
+	 * @param  target	element - the target input field or division or span
+	 */
+	_enableDatepicker: function(target) {
+		var nodeName, inline,
+			$target = $(target),
+			inst = $.data(target, "datepicker");
+
+		if (!$target.hasClass(this.markerClassName)) {
+			return;
+		}
+
+		nodeName = target.nodeName.toLowerCase();
+		if (nodeName === "input") {
+			target.disabled = false;
+			inst.trigger.filter("button").
+				each(function() { this.disabled = false; }).end().
+				filter("img").css({opacity: "1.0", cursor: ""});
+		} else if (nodeName === "div" || nodeName === "span") {
+			inline = $target.children("." + this._inlineClass);
+			inline.children().removeClass("ui-state-disabled");
+			inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+				prop("disabled", false);
+		}
+		this._disabledInputs = $.map(this._disabledInputs,
+			function(value) { return (value === target ? null : value); }); // delete entry
+	},
+
+	/* Disable the date picker to a jQuery selection.
+	 * @param  target	element - the target input field or division or span
+	 */
+	_disableDatepicker: function(target) {
+		var nodeName, inline,
+			$target = $(target),
+			inst = $.data(target, "datepicker");
+
+		if (!$target.hasClass(this.markerClassName)) {
+			return;
+		}
+
+		nodeName = target.nodeName.toLowerCase();
+		if (nodeName === "input") {
+			target.disabled = true;
+			inst.trigger.filter("button").
+				each(function() { this.disabled = true; }).end().
+				filter("img").css({opacity: "0.5", cursor: "default"});
+		} else if (nodeName === "div" || nodeName === "span") {
+			inline = $target.children("." + this._inlineClass);
+			inline.children().addClass("ui-state-disabled");
+			inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+				prop("disabled", true);
+		}
+		this._disabledInputs = $.map(this._disabledInputs,
+			function(value) { return (value === target ? null : value); }); // delete entry
+		this._disabledInputs[this._disabledInputs.length] = target;
+	},
+
+	/* Is the first field in a jQuery collection disabled as a datepicker?
+	 * @param  target	element - the target input field or division or span
+	 * @return boolean - true if disabled, false if enabled
+	 */
+	_isDisabledDatepicker: function(target) {
+		if (!target) {
+			return false;
+		}
+		for (var i = 0; i < this._disabledInputs.length; i++) {
+			if (this._disabledInputs[i] === target) {
+				return true;
+			}
+		}
+		return false;
+	},
+
+	/* Retrieve the instance data for the target control.
+	 * @param  target  element - the target input field or division or span
+	 * @return  object - the associated instance data
+	 * @throws  error if a jQuery problem getting data
+	 */
+	_getInst: function(target) {
+		try {
+			return $.data(target, "datepicker");
+		}
+		catch (err) {
+			throw "Missing instance data for this datepicker";
+		}
+	},
+
+	/* Update or retrieve the settings for a date picker attached to an input field or division.
+	 * @param  target  element - the target input field or division or span
+	 * @param  name	object - the new settings to update or
+	 *				string - the name of the setting to change or retrieve,
+	 *				when retrieving also "all" for all instance settings or
+	 *				"defaults" for all global defaults
+	 * @param  value   any - the new value for the setting
+	 *				(omit if above is an object or to retrieve a value)
+	 */
+	_optionDatepicker: function(target, name, value) {
+		var settings, date, minDate, maxDate,
+			inst = this._getInst(target);
+
+		if (arguments.length === 2 && typeof name === "string") {
+			return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
+				(inst ? (name === "all" ? $.extend({}, inst.settings) :
+				this._get(inst, name)) : null));
+		}
+
+		settings = name || {};
+		if (typeof name === "string") {
+			settings = {};
+			settings[name] = value;
+		}
+
+		if (inst) {
+			if (this._curInst === inst) {
+				this._hideDatepicker();
+			}
+
+			date = this._getDateDatepicker(target, true);
+			minDate = this._getMinMaxDate(inst, "min");
+			maxDate = this._getMinMaxDate(inst, "max");
+			datepicker_extendRemove(inst.settings, settings);
+			// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
+			if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
+				inst.settings.minDate = this._formatDate(inst, minDate);
+			}
+			if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
+				inst.settings.maxDate = this._formatDate(inst, maxDate);
+			}
+			if ( "disabled" in settings ) {
+				if ( settings.disabled ) {
+					this._disableDatepicker(target);
+				} else {
+					this._enableDatepicker(target);
+				}
+			}
+			this._attachments($(target), inst);
+			this._autoSize(inst);
+			this._setDate(inst, date);
+			this._updateAlternate(inst);
+			this._updateDatepicker(inst);
+		}
+	},
+
+	// change method deprecated
+	_changeDatepicker: function(target, name, value) {
+		this._optionDatepicker(target, name, value);
+	},
+
+	/* Redraw the date picker attached to an input field or division.
+	 * @param  target  element - the target input field or division or span
+	 */
+	_refreshDatepicker: function(target) {
+		var inst = this._getInst(target);
+		if (inst) {
+			this._updateDatepicker(inst);
+		}
+	},
+
+	/* Set the dates for a jQuery selection.
+	 * @param  target element - the target input field or division or span
+	 * @param  date	Date - the new date
+	 */
+	_setDateDatepicker: function(target, date) {
+		var inst = this._getInst(target);
+		if (inst) {
+			this._setDate(inst, date);
+			this._updateDatepicker(inst);
+			this._updateAlternate(inst);
+		}
+	},
+
+	/* Get the date(s) for the first entry in a jQuery selection.
+	 * @param  target element - the target input field or division or span
+	 * @param  noDefault boolean - true if no default date is to be used
+	 * @return Date - the current date
+	 */
+	_getDateDatepicker: function(target, noDefault) {
+		var inst = this._getInst(target);
+		if (inst && !inst.inline) {
+			this._setDateFromField(inst, noDefault);
+		}
+		return (inst ? this._getDate(inst) : null);
+	},
+
+	/* Handle keystrokes. */
+	_doKeyDown: function(event) {
+		var onSelect, dateStr, sel,
+			inst = $.datepicker._getInst(event.target),
+			handled = true,
+			isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
+
+		inst._keyEvent = true;
+		if ($.datepicker._datepickerShowing) {
+			switch (event.keyCode) {
+				case 9: $.datepicker._hideDatepicker();
+						handled = false;
+						break; // hide on tab out
+				case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
+									$.datepicker._currentClass + ")", inst.dpDiv);
+						if (sel[0]) {
+							$.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
+						}
+
+						onSelect = $.datepicker._get(inst, "onSelect");
+						if (onSelect) {
+							dateStr = $.datepicker._formatDate(inst);
+
+							// trigger custom callback
+							onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
+						} else {
+							$.datepicker._hideDatepicker();
+						}
+
+						return false; // don't submit the form
+				case 27: $.datepicker._hideDatepicker();
+						break; // hide on escape
+				case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+							-$.datepicker._get(inst, "stepBigMonths") :
+							-$.datepicker._get(inst, "stepMonths")), "M");
+						break; // previous month/year on page up/+ ctrl
+				case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+							+$.datepicker._get(inst, "stepBigMonths") :
+							+$.datepicker._get(inst, "stepMonths")), "M");
+						break; // next month/year on page down/+ ctrl
+				case 35: if (event.ctrlKey || event.metaKey) {
+							$.datepicker._clearDate(event.target);
+						}
+						handled = event.ctrlKey || event.metaKey;
+						break; // clear on ctrl or command +end
+				case 36: if (event.ctrlKey || event.metaKey) {
+							$.datepicker._gotoToday(event.target);
+						}
+						handled = event.ctrlKey || event.metaKey;
+						break; // current on ctrl or command +home
+				case 37: if (event.ctrlKey || event.metaKey) {
+							$.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
+						}
+						handled = event.ctrlKey || event.metaKey;
+						// -1 day on ctrl or command +left
+						if (event.originalEvent.altKey) {
+							$.datepicker._adjustDate(event.target, (event.ctrlKey ?
+								-$.datepicker._get(inst, "stepBigMonths") :
+								-$.datepicker._get(inst, "stepMonths")), "M");
+						}
+						// next month/year on alt +left on Mac
+						break;
+				case 38: if (event.ctrlKey || event.metaKey) {
+							$.datepicker._adjustDate(event.target, -7, "D");
+						}
+						handled = event.ctrlKey || event.metaKey;
+						break; // -1 week on ctrl or command +up
+				case 39: if (event.ctrlKey || event.metaKey) {
+							$.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
+						}
+						handled = event.ctrlKey || event.metaKey;
+						// +1 day on ctrl or command +right
+						if (event.originalEvent.altKey) {
+							$.datepicker._adjustDate(event.target, (event.ctrlKey ?
+								+$.datepicker._get(inst, "stepBigMonths") :
+								+$.datepicker._get(inst, "stepMonths")), "M");
+						}
+						// next month/year on alt +right
+						break;
+				case 40: if (event.ctrlKey || event.metaKey) {
+							$.datepicker._adjustDate(event.target, +7, "D");
+						}
+						handled = event.ctrlKey || event.metaKey;
+						break; // +1 week on ctrl or command +down
+				default: handled = false;
+			}
+		} else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
+			$.datepicker._showDatepicker(this);
+		} else {
+			handled = false;
+		}
+
+		if (handled) {
+			event.preventDefault();
+			event.stopPropagation();
+		}
+	},
+
+	/* Filter entered characters - based on date format. */
+	_doKeyPress: function(event) {
+		var chars, chr,
+			inst = $.datepicker._getInst(event.target);
+
+		if ($.datepicker._get(inst, "constrainInput")) {
+			chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
+			chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
+			return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
+		}
+	},
+
+	/* Synchronise manual entry and field/alternate field. */
+	_doKeyUp: function(event) {
+		var date,
+			inst = $.datepicker._getInst(event.target);
+
+		if (inst.input.val() !== inst.lastVal) {
+			try {
+				date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
+					(inst.input ? inst.input.val() : null),
+					$.datepicker._getFormatConfig(inst));
+
+				if (date) { // only if valid
+					$.datepicker._setDateFromField(inst);
+					$.datepicker._updateAlternate(inst);
+					$.datepicker._updateDatepicker(inst);
+				}
+			}
+			catch (err) {
+			}
+		}
+		return true;
+	},
+
+	/* Pop-up the date picker for a given input field.
+	 * If false returned from beforeShow event handler do not show.
+	 * @param  input  element - the input field attached to the date picker or
+	 *					event - if triggered by focus
+	 */
+	_showDatepicker: function(input) {
+		input = input.target || input;
+		if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
+			input = $("input", input.parentNode)[0];
+		}
+
+		if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
+			return;
+		}
+
+		var inst, beforeShow, beforeShowSettings, isFixed,
+			offset, showAnim, duration;
+
+		inst = $.datepicker._getInst(input);
+		if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
+			$.datepicker._curInst.dpDiv.stop(true, true);
+			if ( inst && $.datepicker._datepickerShowing ) {
+				$.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
+			}
+		}
+
+		beforeShow = $.datepicker._get(inst, "beforeShow");
+		beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
+		if(beforeShowSettings === false){
+			return;
+		}
+		datepicker_extendRemove(inst.settings, beforeShowSettings);
+
+		inst.lastVal = null;
+		$.datepicker._lastInput = input;
+		$.datepicker._setDateFromField(inst);
+
+		if ($.datepicker._inDialog) { // hide cursor
+			input.value = "";
+		}
+		if (!$.datepicker._pos) { // position below input
+			$.datepicker._pos = $.datepicker._findPos(input);
+			$.datepicker._pos[1] += input.offsetHeight; // add the height
+		}
+
+		isFixed = false;
+		$(input).parents().each(function() {
+			isFixed |= $(this).css("position") === "fixed";
+			return !isFixed;
+		});
+
+		offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
+		$.datepicker._pos = null;
+		//to avoid flashes on Firefox
+		inst.dpDiv.empty();
+		// determine sizing offscreen
+		inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
+		$.datepicker._updateDatepicker(inst);
+		// fix width for dynamic number of date pickers
+		// and adjust position before showing
+		offset = $.datepicker._checkOffset(inst, offset, isFixed);
+		inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
+			"static" : (isFixed ? "fixed" : "absolute")), display: "none",
+			left: offset.left + "px", top: offset.top + "px"});
+
+		if (!inst.inline) {
+			showAnim = $.datepicker._get(inst, "showAnim");
+			duration = $.datepicker._get(inst, "duration");
+			inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
+			$.datepicker._datepickerShowing = true;
+
+			if ( $.effects && $.effects.effect[ showAnim ] ) {
+				inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
+			} else {
+				inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
+			}
+
+			if ( $.datepicker._shouldFocusInput( inst ) ) {
+				inst.input.focus();
+			}
+
+			$.datepicker._curInst = inst;
+		}
+	},
+
+	/* Generate the date picker content. */
+	_updateDatepicker: function(inst) {
+		this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
+		datepicker_instActive = inst; // for delegate hover events
+		inst.dpDiv.empty().append(this._generateHTML(inst));
+		this._attachHandlers(inst);
+
+		var origyearshtml,
+			numMonths = this._getNumberOfMonths(inst),
+			cols = numMonths[1],
+			width = 17,
+			activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
+
+		if ( activeCell.length > 0 ) {
+			datepicker_handleMouseover.apply( activeCell.get( 0 ) );
+		}
+
+		inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
+		if (cols > 1) {
+			inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
+		}
+		inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
+			"Class"]("ui-datepicker-multi");
+		inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
+			"Class"]("ui-datepicker-rtl");
+
+		if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
+			inst.input.focus();
+		}
+
+		// deffered render of the years select (to avoid flashes on Firefox)
+		if( inst.yearshtml ){
+			origyearshtml = inst.yearshtml;
+			setTimeout(function(){
+				//assure that inst.yearshtml didn't change.
+				if( origyearshtml === inst.yearshtml && inst.yearshtml ){
+					inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
+				}
+				origyearshtml = inst.yearshtml = null;
+			}, 0);
+		}
+	},
+
+	// #6694 - don't focus the input if it's already focused
+	// this breaks the change event in IE
+	// Support: IE and jQuery <1.9
+	_shouldFocusInput: function( inst ) {
+		return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
+	},
+
+	/* Check positioning to remain on screen. */
+	_checkOffset: function(inst, offset, isFixed) {
+		var dpWidth = inst.dpDiv.outerWidth(),
+			dpHeight = inst.dpDiv.outerHeight(),
+			inputWidth = inst.input ? inst.input.outerWidth() : 0,
+			inputHeight = inst.input ? inst.input.outerHeight() : 0,
+			viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
+			viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
+
+		offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
+		offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
+		offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
+
+		// now check if datepicker is showing outside window viewport - move to a better place if so.
+		offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
+			Math.abs(offset.left + dpWidth - viewWidth) : 0);
+		offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
+			Math.abs(dpHeight + inputHeight) : 0);
+
+		return offset;
+	},
+
+	/* Find an object's position on the screen. */
+	_findPos: function(obj) {
+		var position,
+			inst = this._getInst(obj),
+			isRTL = this._get(inst, "isRTL");
+
+		while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
+			obj = obj[isRTL ? "previousSibling" : "nextSibling"];
+		}
+
+		position = $(obj).offset();
+		return [position.left, position.top];
+	},
+
+	/* Hide the date picker from view.
+	 * @param  input  element - the input field attached to the date picker
+	 */
+	_hideDatepicker: function(input) {
+		var showAnim, duration, postProcess, onClose,
+			inst = this._curInst;
+
+		if (!inst || (input && inst !== $.data(input, "datepicker"))) {
+			return;
+		}
+
+		if (this._datepickerShowing) {
+			showAnim = this._get(inst, "showAnim");
+			duration = this._get(inst, "duration");
+			postProcess = function() {
+				$.datepicker._tidyDialog(inst);
+			};
+
+			// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
+			if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
+				inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
+			} else {
+				inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
+					(showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
+			}
+
+			if (!showAnim) {
+				postProcess();
+			}
+			this._datepickerShowing = false;
+
+			onClose = this._get(inst, "onClose");
+			if (onClose) {
+				onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
+			}
+
+			this._lastInput = null;
+			if (this._inDialog) {
+				this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
+				if ($.blockUI) {
+					$.unblockUI();
+					$("body").append(this.dpDiv);
+				}
+			}
+			this._inDialog = false;
+		}
+	},
+
+	/* Tidy up after a dialog display. */
+	_tidyDialog: function(inst) {
+		inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
+	},
+
+	/* Close date picker if clicked elsewhere. */
+	_checkExternalClick: function(event) {
+		if (!$.datepicker._curInst) {
+			return;
+		}
+
+		var $target = $(event.target),
+			inst = $.datepicker._getInst($target[0]);
+
+		if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
+				$target.parents("#" + $.datepicker._mainDivId).length === 0 &&
+				!$target.hasClass($.datepicker.markerClassName) &&
+				!$target.closest("." + $.datepicker._triggerClass).length &&
+				$.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
+			( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
+				$.datepicker._hideDatepicker();
+		}
+	},
+
+	/* Adjust one of the date sub-fields. */
+	_adjustDate: function(id, offset, period) {
+		var target = $(id),
+			inst = this._getInst(target[0]);
+
+		if (this._isDisabledDatepicker(target[0])) {
+			return;
+		}
+		this._adjustInstDate(inst, offset +
+			(period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
+			period);
+		this._updateDatepicker(inst);
+	},
+
+	/* Action for current link. */
+	_gotoToday: function(id) {
+		var date,
+			target = $(id),
+			inst = this._getInst(target[0]);
+
+		if (this._get(inst, "gotoCurrent") && inst.currentDay) {
+			inst.selectedDay = inst.currentDay;
+			inst.drawMonth = inst.selectedMonth = inst.currentMonth;
+			inst.drawYear = inst.selectedYear = inst.currentYear;
+		} else {
+			date = new Date();
+			inst.selectedDay = date.getDate();
+			inst.drawMonth = inst.selectedMonth = date.getMonth();
+			inst.drawYear = inst.selectedYear = date.getFullYear();
+		}
+		this._notifyChange(inst);
+		this._adjustDate(target);
+	},
+
+	/* Action for selecting a new month/year. */
+	_selectMonthYear: function(id, select, period) {
+		var target = $(id),
+			inst = this._getInst(target[0]);
+
+		inst["selected" + (period === "M" ? "Month" : "Year")] =
+		inst["draw" + (period === "M" ? "Month" : "Year")] =
+			parseInt(select.options[select.selectedIndex].value,10);
+
+		this._notifyChange(inst);
+		this._adjustDate(target);
+	},
+
+	/* Action for selecting a day. */
+	_selectDay: function(id, month, year, td) {
+		var inst,
+			target = $(id);
+
+		if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
+			return;
+		}
+
+		inst = this._getInst(target[0]);
+		inst.selectedDay = inst.currentDay = $("a", td).html();
+		inst.selectedMonth = inst.currentMonth = month;
+		inst.selectedYear = inst.currentYear = year;
+		this._selectDate(id, this._formatDate(inst,
+			inst.currentDay, inst.currentMonth, inst.currentYear));
+	},
+
+	/* Erase the input field and hide the date picker. */
+	_clearDate: function(id) {
+		var target = $(id);
+		this._selectDate(target, "");
+	},
+
+	/* Update the input field with the selected date. */
+	_selectDate: function(id, dateStr) {
+		var onSelect,
+			target = $(id),
+			inst = this._getInst(target[0]);
+
+		dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
+		if (inst.input) {
+			inst.input.val(dateStr);
+		}
+		this._updateAlternate(inst);
+
+		onSelect = this._get(inst, "onSelect");
+		if (onSelect) {
+			onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);  // trigger custom callback
+		} else if (inst.input) {
+			inst.input.trigger("change"); // fire the change event
+		}
+
+		if (inst.inline){
+			this._updateDatepicker(inst);
+		} else {
+			this._hideDatepicker();
+			this._lastInput = inst.input[0];
+			if (typeof(inst.input[0]) !== "object") {
+				inst.input.focus(); // restore focus
+			}
+			this._lastInput = null;
+		}
+	},
+
+	/* Update any alternate field to synchronise with the main field. */
+	_updateAlternate: function(inst) {
+		var altFormat, date, dateStr,
+			altField = this._get(inst, "altField");
+
+		if (altField) { // update alternate field too
+			altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
+			date = this._getDate(inst);
+			dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
+			$(altField).each(function() { $(this).val(dateStr); });
+		}
+	},
+
+	/* Set as beforeShowDay function to prevent selection of weekends.
+	 * @param  date  Date - the date to customise
+	 * @return [boolean, string] - is this date selectable?, what is its CSS class?
+	 */
+	noWeekends: function(date) {
+		var day = date.getDay();
+		return [(day > 0 && day < 6), ""];
+	},
+
+	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
+	 * @param  date  Date - the date to get the week for
+	 * @return  number - the number of the week within the year that contains this date
+	 */
+	iso8601Week: function(date) {
+		var time,
+			checkDate = new Date(date.getTime());
+
+		// Find Thursday of this week starting on Monday
+		checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
+
+		time = checkDate.getTime();
+		checkDate.setMonth(0); // Compare with Jan 1
+		checkDate.setDate(1);
+		return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
+	},
+
+	/* Parse a string value into a date object.
+	 * See formatDate below for the possible formats.
+	 *
+	 * @param  format string - the expected format of the date
+	 * @param  value string - the date in the above format
+	 * @param  settings Object - attributes include:
+	 *					shortYearCutoff  number - the cutoff year for determining the century (optional)
+	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
+	 *					dayNames		string[7] - names of the days from Sunday (optional)
+	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
+	 *					monthNames		string[12] - names of the months (optional)
+	 * @return  Date - the extracted date value or null if value is blank
+	 */
+	parseDate: function (format, value, settings) {
+		if (format == null || value == null) {
+			throw "Invalid arguments";
+		}
+
+		value = (typeof value === "object" ? value.toString() : value + "");
+		if (value === "") {
+			return null;
+		}
+
+		var iFormat, dim, extra,
+			iValue = 0,
+			shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
+			shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
+				new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
+			dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
+			dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
+			monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
+			monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
+			year = -1,
+			month = -1,
+			day = -1,
+			doy = -1,
+			literal = false,
+			date,
+			// Check whether a format character is doubled
+			lookAhead = function(match) {
+				var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+				if (matches) {
+					iFormat++;
+				}
+				return matches;
+			},
+			// Extract a number from the string value
+			getNumber = function(match) {
+				var isDoubled = lookAhead(match),
+					size = (match === "@" ? 14 : (match === "!" ? 20 :
+					(match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
+					minSize = (match === "y" ? size : 1),
+					digits = new RegExp("^\\d{" + minSize + "," + size + "}"),
+					num = value.substring(iValue).match(digits);
+				if (!num) {
+					throw "Missing number at position " + iValue;
+				}
+				iValue += num[0].length;
+				return parseInt(num[0], 10);
+			},
+			// Extract a name from the string value and convert to an index
+			getName = function(match, shortNames, longNames) {
+				var index = -1,
+					names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
+						return [ [k, v] ];
+					}).sort(function (a, b) {
+						return -(a[1].length - b[1].length);
+					});
+
+				$.each(names, function (i, pair) {
+					var name = pair[1];
+					if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
+						index = pair[0];
+						iValue += name.length;
+						return false;
+					}
+				});
+				if (index !== -1) {
+					return index + 1;
+				} else {
+					throw "Unknown name at position " + iValue;
+				}
+			},
+			// Confirm that a literal character matches the string value
+			checkLiteral = function() {
+				if (value.charAt(iValue) !== format.charAt(iFormat)) {
+					throw "Unexpected literal at position " + iValue;
+				}
+				iValue++;
+			};
+
+		for (iFormat = 0; iFormat < format.length; iFormat++) {
+			if (literal) {
+				if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+					literal = false;
+				} else {
+					checkLiteral();
+				}
+			} else {
+				switch (format.charAt(iFormat)) {
+					case "d":
+						day = getNumber("d");
+						break;
+					case "D":
+						getName("D", dayNamesShort, dayNames);
+						break;
+					case "o":
+						doy = getNumber("o");
+						break;
+					case "m":
+						month = getNumber("m");
+						break;
+					case "M":
+						month = getName("M", monthNamesShort, monthNames);
+						break;
+					case "y":
+						year = getNumber("y");
+						break;
+					case "@":
+						date = new Date(getNumber("@"));
+						year = date.getFullYear();
+						month = date.getMonth() + 1;
+						day = date.getDate();
+						break;
+					case "!":
+						date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
+						year = date.getFullYear();
+						month = date.getMonth() + 1;
+						day = date.getDate();
+						break;
+					case "'":
+						if (lookAhead("'")){
+							checkLiteral();
+						} else {
+							literal = true;
+						}
+						break;
+					default:
+						checkLiteral();
+				}
+			}
+		}
+
+		if (iValue < value.length){
+			extra = value.substr(iValue);
+			if (!/^\s+/.test(extra)) {
+				throw "Extra/unparsed characters found in date: " + extra;
+			}
+		}
+
+		if (year === -1) {
+			year = new Date().getFullYear();
+		} else if (year < 100) {
+			year += new Date().getFullYear() - new Date().getFullYear() % 100 +
+				(year <= shortYearCutoff ? 0 : -100);
+		}
+
+		if (doy > -1) {
+			month = 1;
+			day = doy;
+			do {
+				dim = this._getDaysInMonth(year, month - 1);
+				if (day <= dim) {
+					break;
+				}
+				month++;
+				day -= dim;
+			} while (true);
+		}
+
+		date = this._daylightSavingAdjust(new Date(year, month - 1, day));
+		if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
+			throw "Invalid date"; // E.g. 31/02/00
+		}
+		return date;
+	},
+
+	/* Standard date formats. */
+	ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
+	COOKIE: "D, dd M yy",
+	ISO_8601: "yy-mm-dd",
+	RFC_822: "D, d M y",
+	RFC_850: "DD, dd-M-y",
+	RFC_1036: "D, d M y",
+	RFC_1123: "D, d M yy",
+	RFC_2822: "D, d M yy",
+	RSS: "D, d M y", // RFC 822
+	TICKS: "!",
+	TIMESTAMP: "@",
+	W3C: "yy-mm-dd", // ISO 8601
+
+	_ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
+		Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
+
+	/* Format a date object into a string value.
+	 * The format can be combinations of the following:
+	 * d  - day of month (no leading zero)
+	 * dd - day of month (two digit)
+	 * o  - day of year (no leading zeros)
+	 * oo - day of year (three digit)
+	 * D  - day name short
+	 * DD - day name long
+	 * m  - month of year (no leading zero)
+	 * mm - month of year (two digit)
+	 * M  - month name short
+	 * MM - month name long
+	 * y  - year (two digit)
+	 * yy - year (four digit)
+	 * @ - Unix timestamp (ms since 01/01/1970)
+	 * ! - Windows ticks (100ns since 01/01/0001)
+	 * "..." - literal text
+	 * '' - single quote
+	 *
+	 * @param  format string - the desired format of the date
+	 * @param  date Date - the date value to format
+	 * @param  settings Object - attributes include:
+	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
+	 *					dayNames		string[7] - names of the days from Sunday (optional)
+	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
+	 *					monthNames		string[12] - names of the months (optional)
+	 * @return  string - the date in the above format
+	 */
+	formatDate: function (format, date, settings) {
+		if (!date) {
+			return "";
+		}
+
+		var iFormat,
+			dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
+			dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
+			monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
+			monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
+			// Check whether a format character is doubled
+			lookAhead = function(match) {
+				var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+				if (matches) {
+					iFormat++;
+				}
+				return matches;
+			},
+			// Format a number, with leading zero if necessary
+			formatNumber = function(match, value, len) {
+				var num = "" + value;
+				if (lookAhead(match)) {
+					while (num.length < len) {
+						num = "0" + num;
+					}
+				}
+				return num;
+			},
+			// Format a name, short or long as requested
+			formatName = function(match, value, shortNames, longNames) {
+				return (lookAhead(match) ? longNames[value] : shortNames[value]);
+			},
+			output = "",
+			literal = false;
+
+		if (date) {
+			for (iFormat = 0; iFormat < format.length; iFormat++) {
+				if (literal) {
+					if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+						literal = false;
+					} else {
+						output += format.charAt(iFormat);
+					}
+				} else {
+					switch (format.charAt(iFormat)) {
+						case "d":
+							output += formatNumber("d", date.getDate(), 2);
+							break;
+						case "D":
+							output += formatName("D", date.getDay(), dayNamesShort, dayNames);
+							break;
+						case "o":
+							output += formatNumber("o",
+								Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
+							break;
+						case "m":
+							output += formatNumber("m", date.getMonth() + 1, 2);
+							break;
+						case "M":
+							output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
+							break;
+						case "y":
+							output += (lookAhead("y") ? date.getFullYear() :
+								(date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
+							break;
+						case "@":
+							output += date.getTime();
+							break;
+						case "!":
+							output += date.getTime() * 10000 + this._ticksTo1970;
+							break;
+						case "'":
+							if (lookAhead("'")) {
+								output += "'";
+							} else {
+								literal = true;
+							}
+							break;
+						default:
+							output += format.charAt(iFormat);
+					}
+				}
+			}
+		}
+		return output;
+	},
+
+	/* Extract all possible characters from the date format. */
+	_possibleChars: function (format) {
+		var iFormat,
+			chars = "",
+			literal = false,
+			// Check whether a format character is doubled
+			lookAhead = function(match) {
+				var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+				if (matches) {
+					iFormat++;
+				}
+				return matches;
+			};
+
+		for (iFormat = 0; iFormat < format.length; iFormat++) {
+			if (literal) {
+				if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+					literal = false;
+				} else {
+					chars += format.charAt(iFormat);
+				}
+			} else {
+				switch (format.charAt(iFormat)) {
+					case "d": case "m": case "y": case "@":
+						chars += "0123456789";
+						break;
+					case "D": case "M":
+						return null; // Accept anything
+					case "'":
+						if (lookAhead("'")) {
+							chars += "'";
+						} else {
+							literal = true;
+						}
+						break;
+					default:
+						chars += format.charAt(iFormat);
+				}
+			}
+		}
+		return chars;
+	},
+
+	/* Get a setting value, defaulting if necessary. */
+	_get: function(inst, name) {
+		return inst.settings[name] !== undefined ?
+			inst.settings[name] : this._defaults[name];
+	},
+
+	/* Parse existing date and initialise date picker. */
+	_setDateFromField: function(inst, noDefault) {
+		if (inst.input.val() === inst.lastVal) {
+			return;
+		}
+
+		var dateFormat = this._get(inst, "dateFormat"),
+			dates = inst.lastVal = inst.input ? inst.input.val() : null,
+			defaultDate = this._getDefaultDate(inst),
+			date = defaultDate,
+			settings = this._getFormatConfig(inst);
+
+		try {
+			date = this.parseDate(dateFormat, dates, settings) || defaultDate;
+		} catch (event) {
+			dates = (noDefault ? "" : dates);
+		}
+		inst.selectedDay = date.getDate();
+		inst.drawMonth = inst.selectedMonth = date.getMonth();
+		inst.drawYear = inst.selectedYear = date.getFullYear();
+		inst.currentDay = (dates ? date.getDate() : 0);
+		inst.currentMonth = (dates ? date.getMonth() : 0);
+		inst.currentYear = (dates ? date.getFullYear() : 0);
+		this._adjustInstDate(inst);
+	},
+
+	/* Retrieve the default date shown on opening. */
+	_getDefaultDate: function(inst) {
+		return this._restrictMinMax(inst,
+			this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
+	},
+
+	/* A date may be specified as an exact value or a relative one. */
+	_determineDate: function(inst, date, defaultDate) {
+		var offsetNumeric = function(offset) {
+				var date = new Date();
+				date.setDate(date.getDate() + offset);
+				return date;
+			},
+			offsetString = function(offset) {
+				try {
+					return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
+						offset, $.datepicker._getFormatConfig(inst));
+				}
+				catch (e) {
+					// Ignore
+				}
+
+				var date = (offset.toLowerCase().match(/^c/) ?
+					$.datepicker._getDate(inst) : null) || new Date(),
+					year = date.getFullYear(),
+					month = date.getMonth(),
+					day = date.getDate(),
+					pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
+					matches = pattern.exec(offset);
+
+				while (matches) {
+					switch (matches[2] || "d") {
+						case "d" : case "D" :
+							day += parseInt(matches[1],10); break;
+						case "w" : case "W" :
+							day += parseInt(matches[1],10) * 7; break;
+						case "m" : case "M" :
+							month += parseInt(matches[1],10);
+							day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+							break;
+						case "y": case "Y" :
+							year += parseInt(matches[1],10);
+							day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+							break;
+					}
+					matches = pattern.exec(offset);
+				}
+				return new Date(year, month, day);
+			},
+			newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
+				(typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
+
+		newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
+		if (newDate) {
+			newDate.setHours(0);
+			newDate.setMinutes(0);
+			newDate.setSeconds(0);
+			newDate.setMilliseconds(0);
+		}
+		return this._daylightSavingAdjust(newDate);
+	},
+
+	/* Handle switch to/from daylight saving.
+	 * Hours may be non-zero on daylight saving cut-over:
+	 * > 12 when midnight changeover, but then cannot generate
+	 * midnight datetime, so jump to 1AM, otherwise reset.
+	 * @param  date  (Date) the date to check
+	 * @return  (Date) the corrected date
+	 */
+	_daylightSavingAdjust: function(date) {
+		if (!date) {
+			return null;
+		}
+		date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
+		return date;
+	},
+
+	/* Set the date(s) directly. */
+	_setDate: function(inst, date, noChange) {
+		var clear = !date,
+			origMonth = inst.selectedMonth,
+			origYear = inst.selectedYear,
+			newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
+
+		inst.selectedDay = inst.currentDay = newDate.getDate();
+		inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
+		inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
+		if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
+			this._notifyChange(inst);
+		}
+		this._adjustInstDate(inst);
+		if (inst.input) {
+			inst.input.val(clear ? "" : this._formatDate(inst));
+		}
+	},
+
+	/* Retrieve the date(s) directly. */
+	_getDate: function(inst) {
+		var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
+			this._daylightSavingAdjust(new Date(
+			inst.currentYear, inst.currentMonth, inst.currentDay)));
+			return startDate;
+	},
+
+	/* Attach the onxxx handlers.  These are declared statically so
+	 * they work with static code transformers like Caja.
+	 */
+	_attachHandlers: function(inst) {
+		var stepMonths = this._get(inst, "stepMonths"),
+			id = "#" + inst.id.replace( /\\\\/g, "\\" );
+		inst.dpDiv.find("[data-handler]").map(function () {
+			var handler = {
+				prev: function () {
+					$.datepicker._adjustDate(id, -stepMonths, "M");
+				},
+				next: function () {
+					$.datepicker._adjustDate(id, +stepMonths, "M");
+				},
+				hide: function () {
+					$.datepicker._hideDatepicker();
+				},
+				today: function () {
+					$.datepicker._gotoToday(id);
+				},
+				selectDay: function () {
+					$.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
+					return false;
+				},
+				selectMonth: function () {
+					$.datepicker._selectMonthYear(id, this, "M");
+					return false;
+				},
+				selectYear: function () {
+					$.datepicker._selectMonthYear(id, this, "Y");
+					return false;
+				}
+			};
+			$(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
+		});
+	},
+
+	/* Generate the HTML for the current state of the date picker. */
+	_generateHTML: function(inst) {
+		var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
+			controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
+			monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
+			selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
+			cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
+			printDate, dRow, tbody, daySettings, otherMonth, unselectable,
+			tempDate = new Date(),
+			today = this._daylightSavingAdjust(
+				new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
+			isRTL = this._get(inst, "isRTL"),
+			showButtonPanel = this._get(inst, "showButtonPanel"),
+			hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
+			navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
+			numMonths = this._getNumberOfMonths(inst),
+			showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
+			stepMonths = this._get(inst, "stepMonths"),
+			isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
+			currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
+				new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
+			minDate = this._getMinMaxDate(inst, "min"),
+			maxDate = this._getMinMaxDate(inst, "max"),
+			drawMonth = inst.drawMonth - showCurrentAtPos,
+			drawYear = inst.drawYear;
+
+		if (drawMonth < 0) {
+			drawMonth += 12;
+			drawYear--;
+		}
+		if (maxDate) {
+			maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
+				maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
+			maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
+			while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
+				drawMonth--;
+				if (drawMonth < 0) {
+					drawMonth = 11;
+					drawYear--;
+				}
+			}
+		}
+		inst.drawMonth = drawMonth;
+		inst.drawYear = drawYear;
+
+		prevText = this._get(inst, "prevText");
+		prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
+			this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
+			this._getFormatConfig(inst)));
+
+		prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
+			"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
+			" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
+			(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));
+
+		nextText = this._get(inst, "nextText");
+		nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
+			this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
+			this._getFormatConfig(inst)));
+
+		next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
+			"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
+			" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
+			(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));
+
+		currentText = this._get(inst, "currentText");
+		gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
+		currentText = (!navigationAsDateFormat ? currentText :
+			this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
+
+		controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
+			this._get(inst, "closeText") + "</button>" : "");
+
+		buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
+			(this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
+			">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
+
+		firstDay = parseInt(this._get(inst, "firstDay"),10);
+		firstDay = (isNaN(firstDay) ? 0 : firstDay);
+
+		showWeek = this._get(inst, "showWeek");
+		dayNames = this._get(inst, "dayNames");
+		dayNamesMin = this._get(inst, "dayNamesMin");
+		monthNames = this._get(inst, "monthNames");
+		monthNamesShort = this._get(inst, "monthNamesShort");
+		beforeShowDay = this._get(inst, "beforeShowDay");
+		showOtherMonths = this._get(inst, "showOtherMonths");
+		selectOtherMonths = this._get(inst, "selectOtherMonths");
+		defaultDate = this._getDefaultDate(inst);
+		html = "";
+		dow;
+		for (row = 0; row < numMonths[0]; row++) {
+			group = "";
+			this.maxRows = 4;
+			for (col = 0; col < numMonths[1]; col++) {
+				selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
+				cornerClass = " ui-corner-all";
+				calender = "";
+				if (isMultiMonth) {
+					calender += "<div class='ui-datepicker-group";
+					if (numMonths[1] > 1) {
+						switch (col) {
+							case 0: calender += " ui-datepicker-group-first";
+								cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
+							case numMonths[1]-1: calender += " ui-datepicker-group-last";
+								cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
+							default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
+						}
+					}
+					calender += "'>";
+				}
+				calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
+					(/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
+					(/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
+					this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
+					row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
+					"</div><table class='ui-datepicker-calendar'><thead>" +
+					"<tr>";
+				thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
+				for (dow = 0; dow < 7; dow++) { // days of the week
+					day = (dow + firstDay) % 7;
+					thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
+						"<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
+				}
+				calender += thead + "</tr></thead><tbody>";
+				daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
+				if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
+					inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
+				}
+				leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
+				curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
+				numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
+				this.maxRows = numRows;
+				printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
+				for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
+					calender += "<tr>";
+					tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
+						this._get(inst, "calculateWeek")(printDate) + "</td>");
+					for (dow = 0; dow < 7; dow++) { // create date picker days
+						daySettings = (beforeShowDay ?
+							beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
+						otherMonth = (printDate.getMonth() !== drawMonth);
+						unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
+							(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
+						tbody += "<td class='" +
+							((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
+							(otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
+							((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
+							(defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
+							// or defaultDate is current printedDate and defaultDate is selectedDate
+							" " + this._dayOverClass : "") + // highlight selected day
+							(unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") +  // highlight unselectable days
+							(otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
+							(printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
+							(printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
+							((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
+							(unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
+							(otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
+							(unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
+							(printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
+							(printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
+							(otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
+							"' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
+						printDate.setDate(printDate.getDate() + 1);
+						printDate = this._daylightSavingAdjust(printDate);
+					}
+					calender += tbody + "</tr>";
+				}
+				drawMonth++;
+				if (drawMonth > 11) {
+					drawMonth = 0;
+					drawYear++;
+				}
+				calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
+							((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
+				group += calender;
+			}
+			html += group;
+		}
+		html += buttonPanel;
+		inst._keyEvent = false;
+		return html;
+	},
+
+	/* Generate the month and year header. */
+	_generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
+			secondary, monthNames, monthNamesShort) {
+
+		var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
+			changeMonth = this._get(inst, "changeMonth"),
+			changeYear = this._get(inst, "changeYear"),
+			showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
+			html = "<div class='ui-datepicker-title'>",
+			monthHtml = "";
+
+		// month selection
+		if (secondary || !changeMonth) {
+			monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
+		} else {
+			inMinYear = (minDate && minDate.getFullYear() === drawYear);
+			inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
+			monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
+			for ( month = 0; month < 12; month++) {
+				if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
+					monthHtml += "<option value='" + month + "'" +
+						(month === drawMonth ? " selected='selected'" : "") +
+						">" + monthNamesShort[month] + "</option>";
+				}
+			}
+			monthHtml += "</select>";
+		}
+
+		if (!showMonthAfterYear) {
+			html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
+		}
+
+		// year selection
+		if ( !inst.yearshtml ) {
+			inst.yearshtml = "";
+			if (secondary || !changeYear) {
+				html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
+			} else {
+				// determine range of years to display
+				years = this._get(inst, "yearRange").split(":");
+				thisYear = new Date().getFullYear();
+				determineYear = function(value) {
+					var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
+						(value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
+						parseInt(value, 10)));
+					return (isNaN(year) ? thisYear : year);
+				};
+				year = determineYear(years[0]);
+				endYear = Math.max(year, determineYear(years[1] || ""));
+				year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
+				endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
+				inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
+				for (; year <= endYear; year++) {
+					inst.yearshtml += "<option value='" + year + "'" +
+						(year === drawYear ? " selected='selected'" : "") +
+						">" + year + "</option>";
+				}
+				inst.yearshtml += "</select>";
+
+				html += inst.yearshtml;
+				inst.yearshtml = null;
+			}
+		}
+
+		html += this._get(inst, "yearSuffix");
+		if (showMonthAfterYear) {
+			html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
+		}
+		html += "</div>"; // Close datepicker_header
+		return html;
+	},
+
+	/* Adjust one of the date sub-fields. */
+	_adjustInstDate: function(inst, offset, period) {
+		var year = inst.drawYear + (period === "Y" ? offset : 0),
+			month = inst.drawMonth + (period === "M" ? offset : 0),
+			day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
+			date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
+
+		inst.selectedDay = date.getDate();
+		inst.drawMonth = inst.selectedMonth = date.getMonth();
+		inst.drawYear = inst.selectedYear = date.getFullYear();
+		if (period === "M" || period === "Y") {
+			this._notifyChange(inst);
+		}
+	},
+
+	/* Ensure a date is within any min/max bounds. */
+	_restrictMinMax: function(inst, date) {
+		var minDate = this._getMinMaxDate(inst, "min"),
+			maxDate = this._getMinMaxDate(inst, "max"),
+			newDate = (minDate && date < minDate ? minDate : date);
+		return (maxDate && newDate > maxDate ? maxDate : newDate);
+	},
+
+	/* Notify change of month/year. */
+	_notifyChange: function(inst) {
+		var onChange = this._get(inst, "onChangeMonthYear");
+		if (onChange) {
+			onChange.apply((inst.input ? inst.input[0] : null),
+				[inst.selectedYear, inst.selectedMonth + 1, inst]);
+		}
+	},
+
+	/* Determine the number of months to show. */
+	_getNumberOfMonths: function(inst) {
+		var numMonths = this._get(inst, "numberOfMonths");
+		return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
+	},
+
+	/* Determine the current maximum date - ensure no time components are set. */
+	_getMinMaxDate: function(inst, minMax) {
+		return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
+	},
+
+	/* Find the number of days in a given month. */
+	_getDaysInMonth: function(year, month) {
+		return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
+	},
+
+	/* Find the day of the week of the first of a month. */
+	_getFirstDayOfMonth: function(year, month) {
+		return new Date(year, month, 1).getDay();
+	},
+
+	/* Determines if we should allow a "next/prev" month display change. */
+	_canAdjustMonth: function(inst, offset, curYear, curMonth) {
+		var numMonths = this._getNumberOfMonths(inst),
+			date = this._daylightSavingAdjust(new Date(curYear,
+			curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
+
+		if (offset < 0) {
+			date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
+		}
+		return this._isInRange(inst, date);
+	},
+
+	/* Is the given date in the accepted range? */
+	_isInRange: function(inst, date) {
+		var yearSplit, currentYear,
+			minDate = this._getMinMaxDate(inst, "min"),
+			maxDate = this._getMinMaxDate(inst, "max"),
+			minYear = null,
+			maxYear = null,
+			years = this._get(inst, "yearRange");
+			if (years){
+				yearSplit = years.split(":");
+				currentYear = new Date().getFullYear();
+				minYear = parseInt(yearSplit[0], 10);
+				maxYear = parseInt(yearSplit[1], 10);
+				if ( yearSplit[0].match(/[+\-].*/) ) {
+					minYear += currentYear;
+				}
+				if ( yearSplit[1].match(/[+\-].*/) ) {
+					maxYear += currentYear;
+				}
+			}
+
+		return ((!minDate || date.getTime() >= minDate.getTime()) &&
+			(!maxDate || date.getTime() <= maxDate.getTime()) &&
+			(!minYear || date.getFullYear() >= minYear) &&
+			(!maxYear || date.getFullYear() <= maxYear));
+	},
+
+	/* Provide the configuration settings for formatting/parsing. */
+	_getFormatConfig: function(inst) {
+		var shortYearCutoff = this._get(inst, "shortYearCutoff");
+		shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
+			new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
+		return {shortYearCutoff: shortYearCutoff,
+			dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
+			monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
+	},
+
+	/* Format the given date for display. */
+	_formatDate: function(inst, day, month, year) {
+		if (!day) {
+			inst.currentDay = inst.selectedDay;
+			inst.currentMonth = inst.selectedMonth;
+			inst.currentYear = inst.selectedYear;
+		}
+		var date = (day ? (typeof day === "object" ? day :
+			this._daylightSavingAdjust(new Date(year, month, day))) :
+			this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
+		return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
+	}
+});
+
+/*
+ * Bind hover events for datepicker elements.
+ * Done via delegate so the binding only occurs once in the lifetime of the parent div.
+ * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
+ */
+function datepicker_bindHover(dpDiv) {
+	var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
+	return dpDiv.delegate(selector, "mouseout", function() {
+			$(this).removeClass("ui-state-hover");
+			if (this.className.indexOf("ui-datepicker-prev") !== -1) {
+				$(this).removeClass("ui-datepicker-prev-hover");
+			}
+			if (this.className.indexOf("ui-datepicker-next") !== -1) {
+				$(this).removeClass("ui-datepicker-next-hover");
+			}
+		})
+		.delegate( selector, "mouseover", datepicker_handleMouseover );
+}
+
+function datepicker_handleMouseover() {
+	if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) {
+		$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
+		$(this).addClass("ui-state-hover");
+		if (this.className.indexOf("ui-datepicker-prev") !== -1) {
+			$(this).addClass("ui-datepicker-prev-hover");
+		}
+		if (this.className.indexOf("ui-datepicker-next") !== -1) {
+			$(this).addClass("ui-datepicker-next-hover");
+		}
+	}
+}
+
+/* jQuery extend now ignores nulls! */
+function datepicker_extendRemove(target, props) {
+	$.extend(target, props);
+	for (var name in props) {
+		if (props[name] == null) {
+			target[name] = props[name];
+		}
+	}
+	return target;
+}
+
+/* Invoke the datepicker functionality.
+   @param  options  string - a command, optionally followed by additional parameters or
+					Object - settings for attaching new datepicker functionality
+   @return  jQuery object */
+$.fn.datepicker = function(options){
+
+	/* Verify an empty collection wasn't passed - Fixes #6976 */
+	if ( !this.length ) {
+		return this;
+	}
+
+	/* Initialise the date picker. */
+	if (!$.datepicker.initialized) {
+		$(document).mousedown($.datepicker._checkExternalClick);
+		$.datepicker.initialized = true;
+	}
+
+	/* Append datepicker main container to body if not exist. */
+	if ($("#"+$.datepicker._mainDivId).length === 0) {
+		$("body").append($.datepicker.dpDiv);
+	}
+
+	var otherArgs = Array.prototype.slice.call(arguments, 1);
+	if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
+		return $.datepicker["_" + options + "Datepicker"].
+			apply($.datepicker, [this[0]].concat(otherArgs));
+	}
+	if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
+		return $.datepicker["_" + options + "Datepicker"].
+			apply($.datepicker, [this[0]].concat(otherArgs));
+	}
+	return this.each(function() {
+		typeof options === "string" ?
+			$.datepicker["_" + options + "Datepicker"].
+				apply($.datepicker, [this].concat(otherArgs)) :
+			$.datepicker._attachDatepicker(this, options);
+	});
+};
+
+$.datepicker = new Datepicker(); // singleton instance
+$.datepicker.initialized = false;
+$.datepicker.uuid = new Date().getTime();
+$.datepicker.version = "1.11.4";
+
+var datepicker = $.datepicker;
+
+
+/*!
+ * jQuery UI Dialog 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/dialog/
+ */
+
+
+var dialog = $.widget( "ui.dialog", {
+	version: "1.11.4",
+	options: {
+		appendTo: "body",
+		autoOpen: true,
+		buttons: [],
+		closeOnEscape: true,
+		closeText: "Close",
+		dialogClass: "",
+		draggable: true,
+		hide: null,
+		height: "auto",
+		maxHeight: null,
+		maxWidth: null,
+		minHeight: 150,
+		minWidth: 150,
+		modal: false,
+		position: {
+			my: "center",
+			at: "center",
+			of: window,
+			collision: "fit",
+			// Ensure the titlebar is always visible
+			using: function( pos ) {
+				var topOffset = $( this ).css( pos ).offset().top;
+				if ( topOffset < 0 ) {
+					$( this ).css( "top", pos.top - topOffset );
+				}
+			}
+		},
+		resizable: true,
+		show: null,
+		title: null,
+		width: 300,
+
+		// callbacks
+		beforeClose: null,
+		close: null,
+		drag: null,
+		dragStart: null,
+		dragStop: null,
+		focus: null,
+		open: null,
+		resize: null,
+		resizeStart: null,
+		resizeStop: null
+	},
+
+	sizeRelatedOptions: {
+		buttons: true,
+		height: true,
+		maxHeight: true,
+		maxWidth: true,
+		minHeight: true,
+		minWidth: true,
+		width: true
+	},
+
+	resizableRelatedOptions: {
+		maxHeight: true,
+		maxWidth: true,
+		minHeight: true,
+		minWidth: true
+	},
+
+	_create: function() {
+		this.originalCss = {
+			display: this.element[ 0 ].style.display,
+			width: this.element[ 0 ].style.width,
+			minHeight: this.element[ 0 ].style.minHeight,
+			maxHeight: this.element[ 0 ].style.maxHeight,
+			height: this.element[ 0 ].style.height
+		};
+		this.originalPosition = {
+			parent: this.element.parent(),
+			index: this.element.parent().children().index( this.element )
+		};
+		this.originalTitle = this.element.attr( "title" );
+		this.options.title = this.options.title || this.originalTitle;
+
+		this._createWrapper();
+
+		this.element
+			.show()
+			.removeAttr( "title" )
+			.addClass( "ui-dialog-content ui-widget-content" )
+			.appendTo( this.uiDialog );
+
+		this._createTitlebar();
+		this._createButtonPane();
+
+		if ( this.options.draggable && $.fn.draggable ) {
+			this._makeDraggable();
+		}
+		if ( this.options.resizable && $.fn.resizable ) {
+			this._makeResizable();
+		}
+
+		this._isOpen = false;
+
+		this._trackFocus();
+	},
+
+	_init: function() {
+		if ( this.options.autoOpen ) {
+			this.open();
+		}
+	},
+
+	_appendTo: function() {
+		var element = this.options.appendTo;
+		if ( element && (element.jquery || element.nodeType) ) {
+			return $( element );
+		}
+		return this.document.find( element || "body" ).eq( 0 );
+	},
+
+	_destroy: function() {
+		var next,
+			originalPosition = this.originalPosition;
+
+		this._untrackInstance();
+		this._destroyOverlay();
+
+		this.element
+			.removeUniqueId()
+			.removeClass( "ui-dialog-content ui-widget-content" )
+			.css( this.originalCss )
+			// Without detaching first, the following becomes really slow
+			.detach();
+
+		this.uiDialog.stop( true, true ).remove();
+
+		if ( this.originalTitle ) {
+			this.element.attr( "title", this.originalTitle );
+		}
+
+		next = originalPosition.parent.children().eq( originalPosition.index );
+		// Don't try to place the dialog next to itself (#8613)
+		if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
+			next.before( this.element );
+		} else {
+			originalPosition.parent.append( this.element );
+		}
+	},
+
+	widget: function() {
+		return this.uiDialog;
+	},
+
+	disable: $.noop,
+	enable: $.noop,
+
+	close: function( event ) {
+		var activeElement,
+			that = this;
+
+		if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
+			return;
+		}
+
+		this._isOpen = false;
+		this._focusedElement = null;
+		this._destroyOverlay();
+		this._untrackInstance();
+
+		if ( !this.opener.filter( ":focusable" ).focus().length ) {
+
+			// support: IE9
+			// IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
+			try {
+				activeElement = this.document[ 0 ].activeElement;
+
+				// Support: IE9, IE10
+				// If the <body> is blurred, IE will switch windows, see #4520
+				if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
+
+					// Hiding a focused element doesn't trigger blur in WebKit
+					// so in case we have nothing to focus on, explicitly blur the active element
+					// https://bugs.webkit.org/show_bug.cgi?id=47182
+					$( activeElement ).blur();
+				}
+			} catch ( error ) {}
+		}
+
+		this._hide( this.uiDialog, this.options.hide, function() {
+			that._trigger( "close", event );
+		});
+	},
+
+	isOpen: function() {
+		return this._isOpen;
+	},
+
+	moveToTop: function() {
+		this._moveToTop();
+	},
+
+	_moveToTop: function( event, silent ) {
+		var moved = false,
+			zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map(function() {
+				return +$( this ).css( "z-index" );
+			}).get(),
+			zIndexMax = Math.max.apply( null, zIndices );
+
+		if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
+			this.uiDialog.css( "z-index", zIndexMax + 1 );
+			moved = true;
+		}
+
+		if ( moved && !silent ) {
+			this._trigger( "focus", event );
+		}
+		return moved;
+	},
+
+	open: function() {
+		var that = this;
+		if ( this._isOpen ) {
+			if ( this._moveToTop() ) {
+				this._focusTabbable();
+			}
+			return;
+		}
+
+		this._isOpen = true;
+		this.opener = $( this.document[ 0 ].activeElement );
+
+		this._size();
+		this._position();
+		this._createOverlay();
+		this._moveToTop( null, true );
+
+		// Ensure the overlay is moved to the top with the dialog, but only when
+		// opening. The overlay shouldn't move after the dialog is open so that
+		// modeless dialogs opened after the modal dialog stack properly.
+		if ( this.overlay ) {
+			this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
+		}
+
+		this._show( this.uiDialog, this.options.show, function() {
+			that._focusTabbable();
+			that._trigger( "focus" );
+		});
+
+		// Track the dialog immediately upon openening in case a focus event
+		// somehow occurs outside of the dialog before an element inside the
+		// dialog is focused (#10152)
+		this._makeFocusTarget();
+
+		this._trigger( "open" );
+	},
+
+	_focusTabbable: function() {
+		// Set focus to the first match:
+		// 1. An element that was focused previously
+		// 2. First element inside the dialog matching [autofocus]
+		// 3. Tabbable element inside the content element
+		// 4. Tabbable element inside the buttonpane
+		// 5. The close button
+		// 6. The dialog itself
+		var hasFocus = this._focusedElement;
+		if ( !hasFocus ) {
+			hasFocus = this.element.find( "[autofocus]" );
+		}
+		if ( !hasFocus.length ) {
+			hasFocus = this.element.find( ":tabbable" );
+		}
+		if ( !hasFocus.length ) {
+			hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
+		}
+		if ( !hasFocus.length ) {
+			hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
+		}
+		if ( !hasFocus.length ) {
+			hasFocus = this.uiDialog;
+		}
+		hasFocus.eq( 0 ).focus();
+	},
+
+	_keepFocus: function( event ) {
+		function checkFocus() {
+			var activeElement = this.document[0].activeElement,
+				isActive = this.uiDialog[0] === activeElement ||
+					$.contains( this.uiDialog[0], activeElement );
+			if ( !isActive ) {
+				this._focusTabbable();
+			}
+		}
+		event.preventDefault();
+		checkFocus.call( this );
+		// support: IE
+		// IE <= 8 doesn't prevent moving focus even with event.preventDefault()
+		// so we check again later
+		this._delay( checkFocus );
+	},
+
+	_createWrapper: function() {
+		this.uiDialog = $("<div>")
+			.addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
+				this.options.dialogClass )
+			.hide()
+			.attr({
+				// Setting tabIndex makes the div focusable
+				tabIndex: -1,
+				role: "dialog"
+			})
+			.appendTo( this._appendTo() );
+
+		this._on( this.uiDialog, {
+			keydown: function( event ) {
+				if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
+						event.keyCode === $.ui.keyCode.ESCAPE ) {
+					event.preventDefault();
+					this.close( event );
+					return;
+				}
+
+				// prevent tabbing out of dialogs
+				if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
+					return;
+				}
+				var tabbables = this.uiDialog.find( ":tabbable" ),
+					first = tabbables.filter( ":first" ),
+					last = tabbables.filter( ":last" );
+
+				if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
+					this._delay(function() {
+						first.focus();
+					});
+					event.preventDefault();
+				} else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
+					this._delay(function() {
+						last.focus();
+					});
+					event.preventDefault();
+				}
+			},
+			mousedown: function( event ) {
+				if ( this._moveToTop( event ) ) {
+					this._focusTabbable();
+				}
+			}
+		});
+
+		// We assume that any existing aria-describedby attribute means
+		// that the dialog content is marked up properly
+		// otherwise we brute force the content as the description
+		if ( !this.element.find( "[aria-describedby]" ).length ) {
+			this.uiDialog.attr({
+				"aria-describedby": this.element.uniqueId().attr( "id" )
+			});
+		}
+	},
+
+	_createTitlebar: function() {
+		var uiDialogTitle;
+
+		this.uiDialogTitlebar = $( "<div>" )
+			.addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" )
+			.prependTo( this.uiDialog );
+		this._on( this.uiDialogTitlebar, {
+			mousedown: function( event ) {
+				// Don't prevent click on close button (#8838)
+				// Focusing a dialog that is partially scrolled out of view
+				// causes the browser to scroll it into view, preventing the click event
+				if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
+					// Dialog isn't getting focus when dragging (#8063)
+					this.uiDialog.focus();
+				}
+			}
+		});
+
+		// support: IE
+		// Use type="button" to prevent enter keypresses in textboxes from closing the
+		// dialog in IE (#9312)
+		this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
+			.button({
+				label: this.options.closeText,
+				icons: {
+					primary: "ui-icon-closethick"
+				},
+				text: false
+			})
+			.addClass( "ui-dialog-titlebar-close" )
+			.appendTo( this.uiDialogTitlebar );
+		this._on( this.uiDialogTitlebarClose, {
+			click: function( event ) {
+				event.preventDefault();
+				this.close( event );
+			}
+		});
+
+		uiDialogTitle = $( "<span>" )
+			.uniqueId()
+			.addClass( "ui-dialog-title" )
+			.prependTo( this.uiDialogTitlebar );
+		this._title( uiDialogTitle );
+
+		this.uiDialog.attr({
+			"aria-labelledby": uiDialogTitle.attr( "id" )
+		});
+	},
+
+	_title: function( title ) {
+		if ( !this.options.title ) {
+			title.html( "&#160;" );
+		}
+		title.text( this.options.title );
+	},
+
+	_createButtonPane: function() {
+		this.uiDialogButtonPane = $( "<div>" )
+			.addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
+
+		this.uiButtonSet = $( "<div>" )
+			.addClass( "ui-dialog-buttonset" )
+			.appendTo( this.uiDialogButtonPane );
+
+		this._createButtons();
+	},
+
+	_createButtons: function() {
+		var that = this,
+			buttons = this.options.buttons;
+
+		// if we already have a button pane, remove it
+		this.uiDialogButtonPane.remove();
+		this.uiButtonSet.empty();
+
+		if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
+			this.uiDialog.removeClass( "ui-dialog-buttons" );
+			return;
+		}
+
+		$.each( buttons, function( name, props ) {
+			var click, buttonOptions;
+			props = $.isFunction( props ) ?
+				{ click: props, text: name } :
+				props;
+			// Default to a non-submitting button
+			props = $.extend( { type: "button" }, props );
+			// Change the context for the click callback to be the main element
+			click = props.click;
+			props.click = function() {
+				click.apply( that.element[ 0 ], arguments );
+			};
+			buttonOptions = {
+				icons: props.icons,
+				text: props.showText
+			};
+			delete props.icons;
+			delete props.showText;
+			$( "<button></button>", props )
+				.button( buttonOptions )
+				.appendTo( that.uiButtonSet );
+		});
+		this.uiDialog.addClass( "ui-dialog-buttons" );
+		this.uiDialogButtonPane.appendTo( this.uiDialog );
+	},
+
+	_makeDraggable: function() {
+		var that = this,
+			options = this.options;
+
+		function filteredUi( ui ) {
+			return {
+				position: ui.position,
+				offset: ui.offset
+			};
+		}
+
+		this.uiDialog.draggable({
+			cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
+			handle: ".ui-dialog-titlebar",
+			containment: "document",
+			start: function( event, ui ) {
+				$( this ).addClass( "ui-dialog-dragging" );
+				that._blockFrames();
+				that._trigger( "dragStart", event, filteredUi( ui ) );
+			},
+			drag: function( event, ui ) {
+				that._trigger( "drag", event, filteredUi( ui ) );
+			},
+			stop: function( event, ui ) {
+				var left = ui.offset.left - that.document.scrollLeft(),
+					top = ui.offset.top - that.document.scrollTop();
+
+				options.position = {
+					my: "left top",
+					at: "left" + (left >= 0 ? "+" : "") + left + " " +
+						"top" + (top >= 0 ? "+" : "") + top,
+					of: that.window
+				};
+				$( this ).removeClass( "ui-dialog-dragging" );
+				that._unblockFrames();
+				that._trigger( "dragStop", event, filteredUi( ui ) );
+			}
+		});
+	},
+
+	_makeResizable: function() {
+		var that = this,
+			options = this.options,
+			handles = options.resizable,
+			// .ui-resizable has position: relative defined in the stylesheet
+			// but dialogs have to use absolute or fixed positioning
+			position = this.uiDialog.css("position"),
+			resizeHandles = typeof handles === "string" ?
+				handles	:
+				"n,e,s,w,se,sw,ne,nw";
+
+		function filteredUi( ui ) {
+			return {
+				originalPosition: ui.originalPosition,
+				originalSize: ui.originalSize,
+				position: ui.position,
+				size: ui.size
+			};
+		}
+
+		this.uiDialog.resizable({
+			cancel: ".ui-dialog-content",
+			containment: "document",
+			alsoResize: this.element,
+			maxWidth: options.maxWidth,
+			maxHeight: options.maxHeight,
+			minWidth: options.minWidth,
+			minHeight: this._minHeight(),
+			handles: resizeHandles,
+			start: function( event, ui ) {
+				$( this ).addClass( "ui-dialog-resizing" );
+				that._blockFrames();
+				that._trigger( "resizeStart", event, filteredUi( ui ) );
+			},
+			resize: function( event, ui ) {
+				that._trigger( "resize", event, filteredUi( ui ) );
+			},
+			stop: function( event, ui ) {
+				var offset = that.uiDialog.offset(),
+					left = offset.left - that.document.scrollLeft(),
+					top = offset.top - that.document.scrollTop();
+
+				options.height = that.uiDialog.height();
+				options.width = that.uiDialog.width();
+				options.position = {
+					my: "left top",
+					at: "left" + (left >= 0 ? "+" : "") + left + " " +
+						"top" + (top >= 0 ? "+" : "") + top,
+					of: that.window
+				};
+				$( this ).removeClass( "ui-dialog-resizing" );
+				that._unblockFrames();
+				that._trigger( "resizeStop", event, filteredUi( ui ) );
+			}
+		})
+		.css( "position", position );
+	},
+
+	_trackFocus: function() {
+		this._on( this.widget(), {
+			focusin: function( event ) {
+				this._makeFocusTarget();
+				this._focusedElement = $( event.target );
+			}
+		});
+	},
+
+	_makeFocusTarget: function() {
+		this._untrackInstance();
+		this._trackingInstances().unshift( this );
+	},
+
+	_untrackInstance: function() {
+		var instances = this._trackingInstances(),
+			exists = $.inArray( this, instances );
+		if ( exists !== -1 ) {
+			instances.splice( exists, 1 );
+		}
+	},
+
+	_trackingInstances: function() {
+		var instances = this.document.data( "ui-dialog-instances" );
+		if ( !instances ) {
+			instances = [];
+			this.document.data( "ui-dialog-instances", instances );
+		}
+		return instances;
+	},
+
+	_minHeight: function() {
+		var options = this.options;
+
+		return options.height === "auto" ?
+			options.minHeight :
+			Math.min( options.minHeight, options.height );
+	},
+
+	_position: function() {
+		// Need to show the dialog to get the actual offset in the position plugin
+		var isVisible = this.uiDialog.is( ":visible" );
+		if ( !isVisible ) {
+			this.uiDialog.show();
+		}
+		this.uiDialog.position( this.options.position );
+		if ( !isVisible ) {
+			this.uiDialog.hide();
+		}
+	},
+
+	_setOptions: function( options ) {
+		var that = this,
+			resize = false,
+			resizableOptions = {};
+
+		$.each( options, function( key, value ) {
+			that._setOption( key, value );
+
+			if ( key in that.sizeRelatedOptions ) {
+				resize = true;
+			}
+			if ( key in that.resizableRelatedOptions ) {
+				resizableOptions[ key ] = value;
+			}
+		});
+
+		if ( resize ) {
+			this._size();
+			this._position();
+		}
+		if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
+			this.uiDialog.resizable( "option", resizableOptions );
+		}
+	},
+
+	_setOption: function( key, value ) {
+		var isDraggable, isResizable,
+			uiDialog = this.uiDialog;
+
+		if ( key === "dialogClass" ) {
+			uiDialog
+				.removeClass( this.options.dialogClass )
+				.addClass( value );
+		}
+
+		if ( key === "disabled" ) {
+			return;
+		}
+
+		this._super( key, value );
+
+		if ( key === "appendTo" ) {
+			this.uiDialog.appendTo( this._appendTo() );
+		}
+
+		if ( key === "buttons" ) {
+			this._createButtons();
+		}
+
+		if ( key === "closeText" ) {
+			this.uiDialogTitlebarClose.button({
+				// Ensure that we always pass a string
+				label: "" + value
+			});
+		}
+
+		if ( key === "draggable" ) {
+			isDraggable = uiDialog.is( ":data(ui-draggable)" );
+			if ( isDraggable && !value ) {
+				uiDialog.draggable( "destroy" );
+			}
+
+			if ( !isDraggable && value ) {
+				this._makeDraggable();
+			}
+		}
+
+		if ( key === "position" ) {
+			this._position();
+		}
+
+		if ( key === "resizable" ) {
+			// currently resizable, becoming non-resizable
+			isResizable = uiDialog.is( ":data(ui-resizable)" );
+			if ( isResizable && !value ) {
+				uiDialog.resizable( "destroy" );
+			}
+
+			// currently resizable, changing handles
+			if ( isResizable && typeof value === "string" ) {
+				uiDialog.resizable( "option", "handles", value );
+			}
+
+			// currently non-resizable, becoming resizable
+			if ( !isResizable && value !== false ) {
+				this._makeResizable();
+			}
+		}
+
+		if ( key === "title" ) {
+			this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
+		}
+	},
+
+	_size: function() {
+		// If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
+		// divs will both have width and height set, so we need to reset them
+		var nonContentHeight, minContentHeight, maxContentHeight,
+			options = this.options;
+
+		// Reset content sizing
+		this.element.show().css({
+			width: "auto",
+			minHeight: 0,
+			maxHeight: "none",
+			height: 0
+		});
+
+		if ( options.minWidth > options.width ) {
+			options.width = options.minWidth;
+		}
+
+		// reset wrapper sizing
+		// determine the height of all the non-content elements
+		nonContentHeight = this.uiDialog.css({
+				height: "auto",
+				width: options.width
+			})
+			.outerHeight();
+		minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
+		maxContentHeight = typeof options.maxHeight === "number" ?
+			Math.max( 0, options.maxHeight - nonContentHeight ) :
+			"none";
+
+		if ( options.height === "auto" ) {
+			this.element.css({
+				minHeight: minContentHeight,
+				maxHeight: maxContentHeight,
+				height: "auto"
+			});
+		} else {
+			this.element.height( Math.max( 0, options.height - nonContentHeight ) );
+		}
+
+		if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
+			this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
+		}
+	},
+
+	_blockFrames: function() {
+		this.iframeBlocks = this.document.find( "iframe" ).map(function() {
+			var iframe = $( this );
+
+			return $( "<div>" )
+				.css({
+					position: "absolute",
+					width: iframe.outerWidth(),
+					height: iframe.outerHeight()
+				})
+				.appendTo( iframe.parent() )
+				.offset( iframe.offset() )[0];
+		});
+	},
+
+	_unblockFrames: function() {
+		if ( this.iframeBlocks ) {
+			this.iframeBlocks.remove();
+			delete this.iframeBlocks;
+		}
+	},
+
+	_allowInteraction: function( event ) {
+		if ( $( event.target ).closest( ".ui-dialog" ).length ) {
+			return true;
+		}
+
+		// TODO: Remove hack when datepicker implements
+		// the .ui-front logic (#8989)
+		return !!$( event.target ).closest( ".ui-datepicker" ).length;
+	},
+
+	_createOverlay: function() {
+		if ( !this.options.modal ) {
+			return;
+		}
+
+		// We use a delay in case the overlay is created from an
+		// event that we're going to be cancelling (#2804)
+		var isOpening = true;
+		this._delay(function() {
+			isOpening = false;
+		});
+
+		if ( !this.document.data( "ui-dialog-overlays" ) ) {
+
+			// Prevent use of anchors and inputs
+			// Using _on() for an event handler shared across many instances is
+			// safe because the dialogs stack and must be closed in reverse order
+			this._on( this.document, {
+				focusin: function( event ) {
+					if ( isOpening ) {
+						return;
+					}
+
+					if ( !this._allowInteraction( event ) ) {
+						event.preventDefault();
+						this._trackingInstances()[ 0 ]._focusTabbable();
+					}
+				}
+			});
+		}
+
+		this.overlay = $( "<div>" )
+			.addClass( "ui-widget-overlay ui-front" )
+			.appendTo( this._appendTo() );
+		this._on( this.overlay, {
+			mousedown: "_keepFocus"
+		});
+		this.document.data( "ui-dialog-overlays",
+			(this.document.data( "ui-dialog-overlays" ) || 0) + 1 );
+	},
+
+	_destroyOverlay: function() {
+		if ( !this.options.modal ) {
+			return;
+		}
+
+		if ( this.overlay ) {
+			var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
+
+			if ( !overlays ) {
+				this.document
+					.unbind( "focusin" )
+					.removeData( "ui-dialog-overlays" );
+			} else {
+				this.document.data( "ui-dialog-overlays", overlays );
+			}
+
+			this.overlay.remove();
+			this.overlay = null;
+		}
+	}
+});
+
+
+/*!
+ * jQuery UI Progressbar 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/progressbar/
+ */
+
+
+var progressbar = $.widget( "ui.progressbar", {
+	version: "1.11.4",
+	options: {
+		max: 100,
+		value: 0,
+
+		change: null,
+		complete: null
+	},
+
+	min: 0,
+
+	_create: function() {
+		// Constrain initial value
+		this.oldValue = this.options.value = this._constrainedValue();
+
+		this.element
+			.addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+			.attr({
+				// Only set static values, aria-valuenow and aria-valuemax are
+				// set inside _refreshValue()
+				role: "progressbar",
+				"aria-valuemin": this.min
+			});
+
+		this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
+			.appendTo( this.element );
+
+		this._refreshValue();
+	},
+
+	_destroy: function() {
+		this.element
+			.removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+			.removeAttr( "role" )
+			.removeAttr( "aria-valuemin" )
+			.removeAttr( "aria-valuemax" )
+			.removeAttr( "aria-valuenow" );
+
+		this.valueDiv.remove();
+	},
+
+	value: function( newValue ) {
+		if ( newValue === undefined ) {
+			return this.options.value;
+		}
+
+		this.options.value = this._constrainedValue( newValue );
+		this._refreshValue();
+	},
+
+	_constrainedValue: function( newValue ) {
+		if ( newValue === undefined ) {
+			newValue = this.options.value;
+		}
+
+		this.indeterminate = newValue === false;
+
+		// sanitize value
+		if ( typeof newValue !== "number" ) {
+			newValue = 0;
+		}
+
+		return this.indeterminate ? false :
+			Math.min( this.options.max, Math.max( this.min, newValue ) );
+	},
+
+	_setOptions: function( options ) {
+		// Ensure "value" option is set after other values (like max)
+		var value = options.value;
+		delete options.value;
+
+		this._super( options );
+
+		this.options.value = this._constrainedValue( value );
+		this._refreshValue();
+	},
+
+	_setOption: function( key, value ) {
+		if ( key === "max" ) {
+			// Don't allow a max less than min
+			value = Math.max( this.min, value );
+		}
+		if ( key === "disabled" ) {
+			this.element
+				.toggleClass( "ui-state-disabled", !!value )
+				.attr( "aria-disabled", value );
+		}
+		this._super( key, value );
+	},
+
+	_percentage: function() {
+		return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
+	},
+
+	_refreshValue: function() {
+		var value = this.options.value,
+			percentage = this._percentage();
+
+		this.valueDiv
+			.toggle( this.indeterminate || value > this.min )
+			.toggleClass( "ui-corner-right", value === this.options.max )
+			.width( percentage.toFixed(0) + "%" );
+
+		this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
+
+		if ( this.indeterminate ) {
+			this.element.removeAttr( "aria-valuenow" );
+			if ( !this.overlayDiv ) {
+				this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
+			}
+		} else {
+			this.element.attr({
+				"aria-valuemax": this.options.max,
+				"aria-valuenow": value
+			});
+			if ( this.overlayDiv ) {
+				this.overlayDiv.remove();
+				this.overlayDiv = null;
+			}
+		}
+
+		if ( this.oldValue !== value ) {
+			this.oldValue = value;
+			this._trigger( "change" );
+		}
+		if ( value === this.options.max ) {
+			this._trigger( "complete" );
+		}
+	}
+});
+
+
+/*!
+ * jQuery UI Selectmenu 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/selectmenu
+ */
+
+
+var selectmenu = $.widget( "ui.selectmenu", {
+	version: "1.11.4",
+	defaultElement: "<select>",
+	options: {
+		appendTo: null,
+		disabled: null,
+		icons: {
+			button: "ui-icon-triangle-1-s"
+		},
+		position: {
+			my: "left top",
+			at: "left bottom",
+			collision: "none"
+		},
+		width: null,
+
+		// callbacks
+		change: null,
+		close: null,
+		focus: null,
+		open: null,
+		select: null
+	},
+
+	_create: function() {
+		var selectmenuId = this.element.uniqueId().attr( "id" );
+		this.ids = {
+			element: selectmenuId,
+			button: selectmenuId + "-button",
+			menu: selectmenuId + "-menu"
+		};
+
+		this._drawButton();
+		this._drawMenu();
+
+		if ( this.options.disabled ) {
+			this.disable();
+		}
+	},
+
+	_drawButton: function() {
+		var that = this;
+
+		// Associate existing label with the new button
+		this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button );
+		this._on( this.label, {
+			click: function( event ) {
+				this.button.focus();
+				event.preventDefault();
+			}
+		});
+
+		// Hide original select element
+		this.element.hide();
+
+		// Create button
+		this.button = $( "<span>", {
+			"class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all",
+			tabindex: this.options.disabled ? -1 : 0,
+			id: this.ids.button,
+			role: "combobox",
+			"aria-expanded": "false",
+			"aria-autocomplete": "list",
+			"aria-owns": this.ids.menu,
+			"aria-haspopup": "true"
+		})
+			.insertAfter( this.element );
+
+		$( "<span>", {
+			"class": "ui-icon " + this.options.icons.button
+		})
+			.prependTo( this.button );
+
+		this.buttonText = $( "<span>", {
+			"class": "ui-selectmenu-text"
+		})
+			.appendTo( this.button );
+
+		this._setText( this.buttonText, this.element.find( "option:selected" ).text() );
+		this._resizeButton();
+
+		this._on( this.button, this._buttonEvents );
+		this.button.one( "focusin", function() {
+
+			// Delay rendering the menu items until the button receives focus.
+			// The menu may have already been rendered via a programmatic open.
+			if ( !that.menuItems ) {
+				that._refreshMenu();
+			}
+		});
+		this._hoverable( this.button );
+		this._focusable( this.button );
+	},
+
+	_drawMenu: function() {
+		var that = this;
+
+		// Create menu
+		this.menu = $( "<ul>", {
+			"aria-hidden": "true",
+			"aria-labelledby": this.ids.button,
+			id: this.ids.menu
+		});
+
+		// Wrap menu
+		this.menuWrap = $( "<div>", {
+			"class": "ui-selectmenu-menu ui-front"
+		})
+			.append( this.menu )
+			.appendTo( this._appendTo() );
+
+		// Initialize menu widget
+		this.menuInstance = this.menu
+			.menu({
+				role: "listbox",
+				select: function( event, ui ) {
+					event.preventDefault();
+
+					// support: IE8
+					// If the item was selected via a click, the text selection
+					// will be destroyed in IE
+					that._setSelection();
+
+					that._select( ui.item.data( "ui-selectmenu-item" ), event );
+				},
+				focus: function( event, ui ) {
+					var item = ui.item.data( "ui-selectmenu-item" );
+
+					// Prevent inital focus from firing and check if its a newly focused item
+					if ( that.focusIndex != null && item.index !== that.focusIndex ) {
+						that._trigger( "focus", event, { item: item } );
+						if ( !that.isOpen ) {
+							that._select( item, event );
+						}
+					}
+					that.focusIndex = item.index;
+
+					that.button.attr( "aria-activedescendant",
+						that.menuItems.eq( item.index ).attr( "id" ) );
+				}
+			})
+			.menu( "instance" );
+
+		// Adjust menu styles to dropdown
+		this.menu
+			.addClass( "ui-corner-bottom" )
+			.removeClass( "ui-corner-all" );
+
+		// Don't close the menu on mouseleave
+		this.menuInstance._off( this.menu, "mouseleave" );
+
+		// Cancel the menu's collapseAll on document click
+		this.menuInstance._closeOnDocumentClick = function() {
+			return false;
+		};
+
+		// Selects often contain empty items, but never contain dividers
+		this.menuInstance._isDivider = function() {
+			return false;
+		};
+	},
+
+	refresh: function() {
+		this._refreshMenu();
+		this._setText( this.buttonText, this._getSelectedItem().text() );
+		if ( !this.options.width ) {
+			this._resizeButton();
+		}
+	},
+
+	_refreshMenu: function() {
+		this.menu.empty();
+
+		var item,
+			options = this.element.find( "option" );
+
+		if ( !options.length ) {
+			return;
+		}
+
+		this._parseOptions( options );
+		this._renderMenu( this.menu, this.items );
+
+		this.menuInstance.refresh();
+		this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );
+
+		item = this._getSelectedItem();
+
+		// Update the menu to have the correct item focused
+		this.menuInstance.focus( null, item );
+		this._setAria( item.data( "ui-selectmenu-item" ) );
+
+		// Set disabled state
+		this._setOption( "disabled", this.element.prop( "disabled" ) );
+	},
+
+	open: function( event ) {
+		if ( this.options.disabled ) {
+			return;
+		}
+
+		// If this is the first time the menu is being opened, render the items
+		if ( !this.menuItems ) {
+			this._refreshMenu();
+		} else {
+
+			// Menu clears focus on close, reset focus to selected item
+			this.menu.find( ".ui-state-focus" ).removeClass( "ui-state-focus" );
+			this.menuInstance.focus( null, this._getSelectedItem() );
+		}
+
+		this.isOpen = true;
+		this._toggleAttr();
+		this._resizeMenu();
+		this._position();
+
+		this._on( this.document, this._documentClick );
+
+		this._trigger( "open", event );
+	},
+
+	_position: function() {
+		this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
+	},
+
+	close: function( event ) {
+		if ( !this.isOpen ) {
+			return;
+		}
+
+		this.isOpen = false;
+		this._toggleAttr();
+
+		this.range = null;
+		this._off( this.document );
+
+		this._trigger( "close", event );
+	},
+
+	widget: function() {
+		return this.button;
+	},
+
+	menuWidget: function() {
+		return this.menu;
+	},
+
+	_renderMenu: function( ul, items ) {
+		var that = this,
+			currentOptgroup = "";
+
+		$.each( items, function( index, item ) {
+			if ( item.optgroup !== currentOptgroup ) {
+				$( "<li>", {
+					"class": "ui-selectmenu-optgroup ui-menu-divider" +
+						( item.element.parent( "optgroup" ).prop( "disabled" ) ?
+							" ui-state-disabled" :
+							"" ),
+					text: item.optgroup
+				})
+					.appendTo( ul );
+
+				currentOptgroup = item.optgroup;
+			}
+
+			that._renderItemData( ul, item );
+		});
+	},
+
+	_renderItemData: function( ul, item ) {
+		return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
+	},
+
+	_renderItem: function( ul, item ) {
+		var li = $( "<li>" );
+
+		if ( item.disabled ) {
+			li.addClass( "ui-state-disabled" );
+		}
+		this._setText( li, item.label );
+
+		return li.appendTo( ul );
+	},
+
+	_setText: function( element, value ) {
+		if ( value ) {
+			element.text( value );
+		} else {
+			element.html( "&#160;" );
+		}
+	},
+
+	_move: function( direction, event ) {
+		var item, next,
+			filter = ".ui-menu-item";
+
+		if ( this.isOpen ) {
+			item = this.menuItems.eq( this.focusIndex );
+		} else {
+			item = this.menuItems.eq( this.element[ 0 ].selectedIndex );
+			filter += ":not(.ui-state-disabled)";
+		}
+
+		if ( direction === "first" || direction === "last" ) {
+			next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
+		} else {
+			next = item[ direction + "All" ]( filter ).eq( 0 );
+		}
+
+		if ( next.length ) {
+			this.menuInstance.focus( event, next );
+		}
+	},
+
+	_getSelectedItem: function() {
+		return this.menuItems.eq( this.element[ 0 ].selectedIndex );
+	},
+
+	_toggle: function( event ) {
+		this[ this.isOpen ? "close" : "open" ]( event );
+	},
+
+	_setSelection: function() {
+		var selection;
+
+		if ( !this.range ) {
+			return;
+		}
+
+		if ( window.getSelection ) {
+			selection = window.getSelection();
+			selection.removeAllRanges();
+			selection.addRange( this.range );
+
+		// support: IE8
+		} else {
+			this.range.select();
+		}
+
+		// support: IE
+		// Setting the text selection kills the button focus in IE, but
+		// restoring the focus doesn't kill the selection.
+		this.button.focus();
+	},
+
+	_documentClick: {
+		mousedown: function( event ) {
+			if ( !this.isOpen ) {
+				return;
+			}
+
+			if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + this.ids.button ).length ) {
+				this.close( event );
+			}
+		}
+	},
+
+	_buttonEvents: {
+
+		// Prevent text selection from being reset when interacting with the selectmenu (#10144)
+		mousedown: function() {
+			var selection;
+
+			if ( window.getSelection ) {
+				selection = window.getSelection();
+				if ( selection.rangeCount ) {
+					this.range = selection.getRangeAt( 0 );
+				}
+
+			// support: IE8
+			} else {
+				this.range = document.selection.createRange();
+			}
+		},
+
+		click: function( event ) {
+			this._setSelection();
+			this._toggle( event );
+		},
+
+		keydown: function( event ) {
+			var preventDefault = true;
+			switch ( event.keyCode ) {
+				case $.ui.keyCode.TAB:
+				case $.ui.keyCode.ESCAPE:
+					this.close( event );
+					preventDefault = false;
+					break;
+				case $.ui.keyCode.ENTER:
+					if ( this.isOpen ) {
+						this._selectFocusedItem( event );
+					}
+					break;
+				case $.ui.keyCode.UP:
+					if ( event.altKey ) {
+						this._toggle( event );
+					} else {
+						this._move( "prev", event );
+					}
+					break;
+				case $.ui.keyCode.DOWN:
+					if ( event.altKey ) {
+						this._toggle( event );
+					} else {
+						this._move( "next", event );
+					}
+					break;
+				case $.ui.keyCode.SPACE:
+					if ( this.isOpen ) {
+						this._selectFocusedItem( event );
+					} else {
+						this._toggle( event );
+					}
+					break;
+				case $.ui.keyCode.LEFT:
+					this._move( "prev", event );
+					break;
+				case $.ui.keyCode.RIGHT:
+					this._move( "next", event );
+					break;
+				case $.ui.keyCode.HOME:
+				case $.ui.keyCode.PAGE_UP:
+					this._move( "first", event );
+					break;
+				case $.ui.keyCode.END:
+				case $.ui.keyCode.PAGE_DOWN:
+					this._move( "last", event );
+					break;
+				default:
+					this.menu.trigger( event );
+					preventDefault = false;
+			}
+
+			if ( preventDefault ) {
+				event.preventDefault();
+			}
+		}
+	},
+
+	_selectFocusedItem: function( event ) {
+		var item = this.menuItems.eq( this.focusIndex );
+		if ( !item.hasClass( "ui-state-disabled" ) ) {
+			this._select( item.data( "ui-selectmenu-item" ), event );
+		}
+	},
+
+	_select: function( item, event ) {
+		var oldIndex = this.element[ 0 ].selectedIndex;
+
+		// Change native select element
+		this.element[ 0 ].selectedIndex = item.index;
+		this._setText( this.buttonText, item.label );
+		this._setAria( item );
+		this._trigger( "select", event, { item: item } );
+
+		if ( item.index !== oldIndex ) {
+			this._trigger( "change", event, { item: item } );
+		}
+
+		this.close( event );
+	},
+
+	_setAria: function( item ) {
+		var id = this.menuItems.eq( item.index ).attr( "id" );
+
+		this.button.attr({
+			"aria-labelledby": id,
+			"aria-activedescendant": id
+		});
+		this.menu.attr( "aria-activedescendant", id );
+	},
+
+	_setOption: function( key, value ) {
+		if ( key === "icons" ) {
+			this.button.find( "span.ui-icon" )
+				.removeClass( this.options.icons.button )
+				.addClass( value.button );
+		}
+
+		this._super( key, value );
+
+		if ( key === "appendTo" ) {
+			this.menuWrap.appendTo( this._appendTo() );
+		}
+
+		if ( key === "disabled" ) {
+			this.menuInstance.option( "disabled", value );
+			this.button
+				.toggleClass( "ui-state-disabled", value )
+				.attr( "aria-disabled", value );
+
+			this.element.prop( "disabled", value );
+			if ( value ) {
+				this.button.attr( "tabindex", -1 );
+				this.close();
+			} else {
+				this.button.attr( "tabindex", 0 );
+			}
+		}
+
+		if ( key === "width" ) {
+			this._resizeButton();
+		}
+	},
+
+	_appendTo: function() {
+		var element = this.options.appendTo;
+
+		if ( element ) {
+			element = element.jquery || element.nodeType ?
+				$( element ) :
+				this.document.find( element ).eq( 0 );
+		}
+
+		if ( !element || !element[ 0 ] ) {
+			element = this.element.closest( ".ui-front" );
+		}
+
+		if ( !element.length ) {
+			element = this.document[ 0 ].body;
+		}
+
+		return element;
+	},
+
+	_toggleAttr: function() {
+		this.button
+			.toggleClass( "ui-corner-top", this.isOpen )
+			.toggleClass( "ui-corner-all", !this.isOpen )
+			.attr( "aria-expanded", this.isOpen );
+		this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
+		this.menu.attr( "aria-hidden", !this.isOpen );
+	},
+
+	_resizeButton: function() {
+		var width = this.options.width;
+
+		if ( !width ) {
+			width = this.element.show().outerWidth();
+			this.element.hide();
+		}
+
+		this.button.outerWidth( width );
+	},
+
+	_resizeMenu: function() {
+		this.menu.outerWidth( Math.max(
+			this.button.outerWidth(),
+
+			// support: IE10
+			// IE10 wraps long text (possibly a rounding bug)
+			// so we add 1px to avoid the wrapping
+			this.menu.width( "" ).outerWidth() + 1
+		) );
+	},
+
+	_getCreateOptions: function() {
+		return { disabled: this.element.prop( "disabled" ) };
+	},
+
+	_parseOptions: function( options ) {
+		var data = [];
+		options.each(function( index, item ) {
+			var option = $( item ),
+				optgroup = option.parent( "optgroup" );
+			data.push({
+				element: option,
+				index: index,
+				value: option.val(),
+				label: option.text(),
+				optgroup: optgroup.attr( "label" ) || "",
+				disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
+			});
+		});
+		this.items = data;
+	},
+
+	_destroy: function() {
+		this.menuWrap.remove();
+		this.button.remove();
+		this.element.show();
+		this.element.removeUniqueId();
+		this.label.attr( "for", this.ids.element );
+	}
+});
+
+
+/*!
+ * jQuery UI Slider 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/slider/
+ */
+
+
+var slider = $.widget( "ui.slider", $.ui.mouse, {
+	version: "1.11.4",
+	widgetEventPrefix: "slide",
+
+	options: {
+		animate: false,
+		distance: 0,
+		max: 100,
+		min: 0,
+		orientation: "horizontal",
+		range: false,
+		step: 1,
+		value: 0,
+		values: null,
+
+		// callbacks
+		change: null,
+		slide: null,
+		start: null,
+		stop: null
+	},
+
+	// number of pages in a slider
+	// (how many times can you page up/down to go through the whole range)
+	numPages: 5,
+
+	_create: function() {
+		this._keySliding = false;
+		this._mouseSliding = false;
+		this._animateOff = true;
+		this._handleIndex = null;
+		this._detectOrientation();
+		this._mouseInit();
+		this._calculateNewMax();
+
+		this.element
+			.addClass( "ui-slider" +
+				" ui-slider-" + this.orientation +
+				" ui-widget" +
+				" ui-widget-content" +
+				" ui-corner-all");
+
+		this._refresh();
+		this._setOption( "disabled", this.options.disabled );
+
+		this._animateOff = false;
+	},
+
+	_refresh: function() {
+		this._createRange();
+		this._createHandles();
+		this._setupEvents();
+		this._refreshValue();
+	},
+
+	_createHandles: function() {
+		var i, handleCount,
+			options = this.options,
+			existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
+			handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",
+			handles = [];
+
+		handleCount = ( options.values && options.values.length ) || 1;
+
+		if ( existingHandles.length > handleCount ) {
+			existingHandles.slice( handleCount ).remove();
+			existingHandles = existingHandles.slice( 0, handleCount );
+		}
+
+		for ( i = existingHandles.length; i < handleCount; i++ ) {
+			handles.push( handle );
+		}
+
+		this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
+
+		this.handle = this.handles.eq( 0 );
+
+		this.handles.each(function( i ) {
+			$( this ).data( "ui-slider-handle-index", i );
+		});
+	},
+
+	_createRange: function() {
+		var options = this.options,
+			classes = "";
+
+		if ( options.range ) {
+			if ( options.range === true ) {
+				if ( !options.values ) {
+					options.values = [ this._valueMin(), this._valueMin() ];
+				} else if ( options.values.length && options.values.length !== 2 ) {
+					options.values = [ options.values[0], options.values[0] ];
+				} else if ( $.isArray( options.values ) ) {
+					options.values = options.values.slice(0);
+				}
+			}
+
+			if ( !this.range || !this.range.length ) {
+				this.range = $( "<div></div>" )
+					.appendTo( this.element );
+
+				classes = "ui-slider-range" +
+				// note: this isn't the most fittingly semantic framework class for this element,
+				// but worked best visually with a variety of themes
+				" ui-widget-header ui-corner-all";
+			} else {
+				this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
+					// Handle range switching from true to min/max
+					.css({
+						"left": "",
+						"bottom": ""
+					});
+			}
+
+			this.range.addClass( classes +
+				( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
+		} else {
+			if ( this.range ) {
+				this.range.remove();
+			}
+			this.range = null;
+		}
+	},
+
+	_setupEvents: function() {
+		this._off( this.handles );
+		this._on( this.handles, this._handleEvents );
+		this._hoverable( this.handles );
+		this._focusable( this.handles );
+	},
+
+	_destroy: function() {
+		this.handles.remove();
+		if ( this.range ) {
+			this.range.remove();
+		}
+
+		this.element
+			.removeClass( "ui-slider" +
+				" ui-slider-horizontal" +
+				" ui-slider-vertical" +
+				" ui-widget" +
+				" ui-widget-content" +
+				" ui-corner-all" );
+
+		this._mouseDestroy();
+	},
+
+	_mouseCapture: function( event ) {
+		var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
+			that = this,
+			o = this.options;
+
+		if ( o.disabled ) {
+			return false;
+		}
+
+		this.elementSize = {
+			width: this.element.outerWidth(),
+			height: this.element.outerHeight()
+		};
+		this.elementOffset = this.element.offset();
+
+		position = { x: event.pageX, y: event.pageY };
+		normValue = this._normValueFromMouse( position );
+		distance = this._valueMax() - this._valueMin() + 1;
+		this.handles.each(function( i ) {
+			var thisDistance = Math.abs( normValue - that.values(i) );
+			if (( distance > thisDistance ) ||
+				( distance === thisDistance &&
+					(i === that._lastChangedValue || that.values(i) === o.min ))) {
+				distance = thisDistance;
+				closestHandle = $( this );
+				index = i;
+			}
+		});
+
+		allowed = this._start( event, index );
+		if ( allowed === false ) {
+			return false;
+		}
+		this._mouseSliding = true;
+
+		this._handleIndex = index;
+
+		closestHandle
+			.addClass( "ui-state-active" )
+			.focus();
+
+		offset = closestHandle.offset();
+		mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
+		this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
+			left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
+			top: event.pageY - offset.top -
+				( closestHandle.height() / 2 ) -
+				( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
+				( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
+				( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
+		};
+
+		if ( !this.handles.hasClass( "ui-state-hover" ) ) {
+			this._slide( event, index, normValue );
+		}
+		this._animateOff = true;
+		return true;
+	},
+
+	_mouseStart: function() {
+		return true;
+	},
+
+	_mouseDrag: function( event ) {
+		var position = { x: event.pageX, y: event.pageY },
+			normValue = this._normValueFromMouse( position );
+
+		this._slide( event, this._handleIndex, normValue );
+
+		return false;
+	},
+
+	_mouseStop: function( event ) {
+		this.handles.removeClass( "ui-state-active" );
+		this._mouseSliding = false;
+
+		this._stop( event, this._handleIndex );
+		this._change( event, this._handleIndex );
+
+		this._handleIndex = null;
+		this._clickOffset = null;
+		this._animateOff = false;
+
+		return false;
+	},
+
+	_detectOrientation: function() {
+		this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
+	},
+
+	_normValueFromMouse: function( position ) {
+		var pixelTotal,
+			pixelMouse,
+			percentMouse,
+			valueTotal,
+			valueMouse;
+
+		if ( this.orientation === "horizontal" ) {
+			pixelTotal = this.elementSize.width;
+			pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
+		} else {
+			pixelTotal = this.elementSize.height;
+			pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
+		}
+
+		percentMouse = ( pixelMouse / pixelTotal );
+		if ( percentMouse > 1 ) {
+			percentMouse = 1;
+		}
+		if ( percentMouse < 0 ) {
+			percentMouse = 0;
+		}
+		if ( this.orientation === "vertical" ) {
+			percentMouse = 1 - percentMouse;
+		}
+
+		valueTotal = this._valueMax() - this._valueMin();
+		valueMouse = this._valueMin() + percentMouse * valueTotal;
+
+		return this._trimAlignValue( valueMouse );
+	},
+
+	_start: function( event, index ) {
+		var uiHash = {
+			handle: this.handles[ index ],
+			value: this.value()
+		};
+		if ( this.options.values && this.options.values.length ) {
+			uiHash.value = this.values( index );
+			uiHash.values = this.values();
+		}
+		return this._trigger( "start", event, uiHash );
+	},
+
+	_slide: function( event, index, newVal ) {
+		var otherVal,
+			newValues,
+			allowed;
+
+		if ( this.options.values && this.options.values.length ) {
+			otherVal = this.values( index ? 0 : 1 );
+
+			if ( ( this.options.values.length === 2 && this.options.range === true ) &&
+					( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
+				) {
+				newVal = otherVal;
+			}
+
+			if ( newVal !== this.values( index ) ) {
+				newValues = this.values();
+				newValues[ index ] = newVal;
+				// A slide can be canceled by returning false from the slide callback
+				allowed = this._trigger( "slide", event, {
+					handle: this.handles[ index ],
+					value: newVal,
+					values: newValues
+				} );
+				otherVal = this.values( index ? 0 : 1 );
+				if ( allowed !== false ) {
+					this.values( index, newVal );
+				}
+			}
+		} else {
+			if ( newVal !== this.value() ) {
+				// A slide can be canceled by returning false from the slide callback
+				allowed = this._trigger( "slide", event, {
+					handle: this.handles[ index ],
+					value: newVal
+				} );
+				if ( allowed !== false ) {
+					this.value( newVal );
+				}
+			}
+		}
+	},
+
+	_stop: function( event, index ) {
+		var uiHash = {
+			handle: this.handles[ index ],
+			value: this.value()
+		};
+		if ( this.options.values && this.options.values.length ) {
+			uiHash.value = this.values( index );
+			uiHash.values = this.values();
+		}
+
+		this._trigger( "stop", event, uiHash );
+	},
+
+	_change: function( event, index ) {
+		if ( !this._keySliding && !this._mouseSliding ) {
+			var uiHash = {
+				handle: this.handles[ index ],
+				value: this.value()
+			};
+			if ( this.options.values && this.options.values.length ) {
+				uiHash.value = this.values( index );
+				uiHash.values = this.values();
+			}
+
+			//store the last changed value index for reference when handles overlap
+			this._lastChangedValue = index;
+
+			this._trigger( "change", event, uiHash );
+		}
+	},
+
+	value: function( newValue ) {
+		if ( arguments.length ) {
+			this.options.value = this._trimAlignValue( newValue );
+			this._refreshValue();
+			this._change( null, 0 );
+			return;
+		}
+
+		return this._value();
+	},
+
+	values: function( index, newValue ) {
+		var vals,
+			newValues,
+			i;
+
+		if ( arguments.length > 1 ) {
+			this.options.values[ index ] = this._trimAlignValue( newValue );
+			this._refreshValue();
+			this._change( null, index );
+			return;
+		}
+
+		if ( arguments.length ) {
+			if ( $.isArray( arguments[ 0 ] ) ) {
+				vals = this.options.values;
+				newValues = arguments[ 0 ];
+				for ( i = 0; i < vals.length; i += 1 ) {
+					vals[ i ] = this._trimAlignValue( newValues[ i ] );
+					this._change( null, i );
+				}
+				this._refreshValue();
+			} else {
+				if ( this.options.values && this.options.values.length ) {
+					return this._values( index );
+				} else {
+					return this.value();
+				}
+			}
+		} else {
+			return this._values();
+		}
+	},
+
+	_setOption: function( key, value ) {
+		var i,
+			valsLength = 0;
+
+		if ( key === "range" && this.options.range === true ) {
+			if ( value === "min" ) {
+				this.options.value = this._values( 0 );
+				this.options.values = null;
+			} else if ( value === "max" ) {
+				this.options.value = this._values( this.options.values.length - 1 );
+				this.options.values = null;
+			}
+		}
+
+		if ( $.isArray( this.options.values ) ) {
+			valsLength = this.options.values.length;
+		}
+
+		if ( key === "disabled" ) {
+			this.element.toggleClass( "ui-state-disabled", !!value );
+		}
+
+		this._super( key, value );
+
+		switch ( key ) {
+			case "orientation":
+				this._detectOrientation();
+				this.element
+					.removeClass( "ui-slider-horizontal ui-slider-vertical" )
+					.addClass( "ui-slider-" + this.orientation );
+				this._refreshValue();
+
+				// Reset positioning from previous orientation
+				this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
+				break;
+			case "value":
+				this._animateOff = true;
+				this._refreshValue();
+				this._change( null, 0 );
+				this._animateOff = false;
+				break;
+			case "values":
+				this._animateOff = true;
+				this._refreshValue();
+				for ( i = 0; i < valsLength; i += 1 ) {
+					this._change( null, i );
+				}
+				this._animateOff = false;
+				break;
+			case "step":
+			case "min":
+			case "max":
+				this._animateOff = true;
+				this._calculateNewMax();
+				this._refreshValue();
+				this._animateOff = false;
+				break;
+			case "range":
+				this._animateOff = true;
+				this._refresh();
+				this._animateOff = false;
+				break;
+		}
+	},
+
+	//internal value getter
+	// _value() returns value trimmed by min and max, aligned by step
+	_value: function() {
+		var val = this.options.value;
+		val = this._trimAlignValue( val );
+
+		return val;
+	},
+
+	//internal values getter
+	// _values() returns array of values trimmed by min and max, aligned by step
+	// _values( index ) returns single value trimmed by min and max, aligned by step
+	_values: function( index ) {
+		var val,
+			vals,
+			i;
+
+		if ( arguments.length ) {
+			val = this.options.values[ index ];
+			val = this._trimAlignValue( val );
+
+			return val;
+		} else if ( this.options.values && this.options.values.length ) {
+			// .slice() creates a copy of the array
+			// this copy gets trimmed by min and max and then returned
+			vals = this.options.values.slice();
+			for ( i = 0; i < vals.length; i += 1) {
+				vals[ i ] = this._trimAlignValue( vals[ i ] );
+			}
+
+			return vals;
+		} else {
+			return [];
+		}
+	},
+
+	// returns the step-aligned value that val is closest to, between (inclusive) min and max
+	_trimAlignValue: function( val ) {
+		if ( val <= this._valueMin() ) {
+			return this._valueMin();
+		}
+		if ( val >= this._valueMax() ) {
+			return this._valueMax();
+		}
+		var step = ( this.options.step > 0 ) ? this.options.step : 1,
+			valModStep = (val - this._valueMin()) % step,
+			alignValue = val - valModStep;
+
+		if ( Math.abs(valModStep) * 2 >= step ) {
+			alignValue += ( valModStep > 0 ) ? step : ( -step );
+		}
+
+		// Since JavaScript has problems with large floats, round
+		// the final value to 5 digits after the decimal point (see #4124)
+		return parseFloat( alignValue.toFixed(5) );
+	},
+
+	_calculateNewMax: function() {
+		var max = this.options.max,
+			min = this._valueMin(),
+			step = this.options.step,
+			aboveMin = Math.floor( ( +( max - min ).toFixed( this._precision() ) ) / step ) * step;
+		max = aboveMin + min;
+		this.max = parseFloat( max.toFixed( this._precision() ) );
+	},
+
+	_precision: function() {
+		var precision = this._precisionOf( this.options.step );
+		if ( this.options.min !== null ) {
+			precision = Math.max( precision, this._precisionOf( this.options.min ) );
+		}
+		return precision;
+	},
+
+	_precisionOf: function( num ) {
+		var str = num.toString(),
+			decimal = str.indexOf( "." );
+		return decimal === -1 ? 0 : str.length - decimal - 1;
+	},
+
+	_valueMin: function() {
+		return this.options.min;
+	},
+
+	_valueMax: function() {
+		return this.max;
+	},
+
+	_refreshValue: function() {
+		var lastValPercent, valPercent, value, valueMin, valueMax,
+			oRange = this.options.range,
+			o = this.options,
+			that = this,
+			animate = ( !this._animateOff ) ? o.animate : false,
+			_set = {};
+
+		if ( this.options.values && this.options.values.length ) {
+			this.handles.each(function( i ) {
+				valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
+				_set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+				$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+				if ( that.options.range === true ) {
+					if ( that.orientation === "horizontal" ) {
+						if ( i === 0 ) {
+							that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
+						}
+						if ( i === 1 ) {
+							that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+						}
+					} else {
+						if ( i === 0 ) {
+							that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
+						}
+						if ( i === 1 ) {
+							that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+						}
+					}
+				}
+				lastValPercent = valPercent;
+			});
+		} else {
+			value = this.value();
+			valueMin = this._valueMin();
+			valueMax = this._valueMax();
+			valPercent = ( valueMax !== valueMin ) ?
+					( value - valueMin ) / ( valueMax - valueMin ) * 100 :
+					0;
+			_set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+			this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+
+			if ( oRange === "min" && this.orientation === "horizontal" ) {
+				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
+			}
+			if ( oRange === "max" && this.orientation === "horizontal" ) {
+				this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+			}
+			if ( oRange === "min" && this.orientation === "vertical" ) {
+				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
+			}
+			if ( oRange === "max" && this.orientation === "vertical" ) {
+				this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+			}
+		}
+	},
+
+	_handleEvents: {
+		keydown: function( event ) {
+			var allowed, curVal, newVal, step,
+				index = $( event.target ).data( "ui-slider-handle-index" );
+
+			switch ( event.keyCode ) {
+				case $.ui.keyCode.HOME:
+				case $.ui.keyCode.END:
+				case $.ui.keyCode.PAGE_UP:
+				case $.ui.keyCode.PAGE_DOWN:
+				case $.ui.keyCode.UP:
+				case $.ui.keyCode.RIGHT:
+				case $.ui.keyCode.DOWN:
+				case $.ui.keyCode.LEFT:
+					event.preventDefault();
+					if ( !this._keySliding ) {
+						this._keySliding = true;
+						$( event.target ).addClass( "ui-state-active" );
+						allowed = this._start( event, index );
+						if ( allowed === false ) {
+							return;
+						}
+					}
+					break;
+			}
+
+			step = this.options.step;
+			if ( this.options.values && this.options.values.length ) {
+				curVal = newVal = this.values( index );
+			} else {
+				curVal = newVal = this.value();
+			}
+
+			switch ( event.keyCode ) {
+				case $.ui.keyCode.HOME:
+					newVal = this._valueMin();
+					break;
+				case $.ui.keyCode.END:
+					newVal = this._valueMax();
+					break;
+				case $.ui.keyCode.PAGE_UP:
+					newVal = this._trimAlignValue(
+						curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
+					);
+					break;
+				case $.ui.keyCode.PAGE_DOWN:
+					newVal = this._trimAlignValue(
+						curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) );
+					break;
+				case $.ui.keyCode.UP:
+				case $.ui.keyCode.RIGHT:
+					if ( curVal === this._valueMax() ) {
+						return;
+					}
+					newVal = this._trimAlignValue( curVal + step );
+					break;
+				case $.ui.keyCode.DOWN:
+				case $.ui.keyCode.LEFT:
+					if ( curVal === this._valueMin() ) {
+						return;
+					}
+					newVal = this._trimAlignValue( curVal - step );
+					break;
+			}
+
+			this._slide( event, index, newVal );
+		},
+		keyup: function( event ) {
+			var index = $( event.target ).data( "ui-slider-handle-index" );
+
+			if ( this._keySliding ) {
+				this._keySliding = false;
+				this._stop( event, index );
+				this._change( event, index );
+				$( event.target ).removeClass( "ui-state-active" );
+			}
+		}
+	}
+});
+
+
+/*!
+ * jQuery UI Spinner 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/spinner/
+ */
+
+
+function spinner_modifier( fn ) {
+	return function() {
+		var previous = this.element.val();
+		fn.apply( this, arguments );
+		this._refresh();
+		if ( previous !== this.element.val() ) {
+			this._trigger( "change" );
+		}
+	};
+}
+
+var spinner = $.widget( "ui.spinner", {
+	version: "1.11.4",
+	defaultElement: "<input>",
+	widgetEventPrefix: "spin",
+	options: {
+		culture: null,
+		icons: {
+			down: "ui-icon-triangle-1-s",
+			up: "ui-icon-triangle-1-n"
+		},
+		incremental: true,
+		max: null,
+		min: null,
+		numberFormat: null,
+		page: 10,
+		step: 1,
+
+		change: null,
+		spin: null,
+		start: null,
+		stop: null
+	},
+
+	_create: function() {
+		// handle string values that need to be parsed
+		this._setOption( "max", this.options.max );
+		this._setOption( "min", this.options.min );
+		this._setOption( "step", this.options.step );
+
+		// Only format if there is a value, prevents the field from being marked
+		// as invalid in Firefox, see #9573.
+		if ( this.value() !== "" ) {
+			// Format the value, but don't constrain.
+			this._value( this.element.val(), true );
+		}
+
+		this._draw();
+		this._on( this._events );
+		this._refresh();
+
+		// turning off autocomplete prevents the browser from remembering the
+		// value when navigating through history, so we re-enable autocomplete
+		// if the page is unloaded before the widget is destroyed. #7790
+		this._on( this.window, {
+			beforeunload: function() {
+				this.element.removeAttr( "autocomplete" );
+			}
+		});
+	},
+
+	_getCreateOptions: function() {
+		var options = {},
+			element = this.element;
+
+		$.each( [ "min", "max", "step" ], function( i, option ) {
+			var value = element.attr( option );
+			if ( value !== undefined && value.length ) {
+				options[ option ] = value;
+			}
+		});
+
+		return options;
+	},
+
+	_events: {
+		keydown: function( event ) {
+			if ( this._start( event ) && this._keydown( event ) ) {
+				event.preventDefault();
+			}
+		},
+		keyup: "_stop",
+		focus: function() {
+			this.previous = this.element.val();
+		},
+		blur: function( event ) {
+			if ( this.cancelBlur ) {
+				delete this.cancelBlur;
+				return;
+			}
+
+			this._stop();
+			this._refresh();
+			if ( this.previous !== this.element.val() ) {
+				this._trigger( "change", event );
+			}
+		},
+		mousewheel: function( event, delta ) {
+			if ( !delta ) {
+				return;
+			}
+			if ( !this.spinning && !this._start( event ) ) {
+				return false;
+			}
+
+			this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
+			clearTimeout( this.mousewheelTimer );
+			this.mousewheelTimer = this._delay(function() {
+				if ( this.spinning ) {
+					this._stop( event );
+				}
+			}, 100 );
+			event.preventDefault();
+		},
+		"mousedown .ui-spinner-button": function( event ) {
+			var previous;
+
+			// We never want the buttons to have focus; whenever the user is
+			// interacting with the spinner, the focus should be on the input.
+			// If the input is focused then this.previous is properly set from
+			// when the input first received focus. If the input is not focused
+			// then we need to set this.previous based on the value before spinning.
+			previous = this.element[0] === this.document[0].activeElement ?
+				this.previous : this.element.val();
+			function checkFocus() {
+				var isActive = this.element[0] === this.document[0].activeElement;
+				if ( !isActive ) {
+					this.element.focus();
+					this.previous = previous;
+					// support: IE
+					// IE sets focus asynchronously, so we need to check if focus
+					// moved off of the input because the user clicked on the button.
+					this._delay(function() {
+						this.previous = previous;
+					});
+				}
+			}
+
+			// ensure focus is on (or stays on) the text field
+			event.preventDefault();
+			checkFocus.call( this );
+
+			// support: IE
+			// IE doesn't prevent moving focus even with event.preventDefault()
+			// so we set a flag to know when we should ignore the blur event
+			// and check (again) if focus moved off of the input.
+			this.cancelBlur = true;
+			this._delay(function() {
+				delete this.cancelBlur;
+				checkFocus.call( this );
+			});
+
+			if ( this._start( event ) === false ) {
+				return;
+			}
+
+			this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
+		},
+		"mouseup .ui-spinner-button": "_stop",
+		"mouseenter .ui-spinner-button": function( event ) {
+			// button will add ui-state-active if mouse was down while mouseleave and kept down
+			if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
+				return;
+			}
+
+			if ( this._start( event ) === false ) {
+				return false;
+			}
+			this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
+		},
+		// TODO: do we really want to consider this a stop?
+		// shouldn't we just stop the repeater and wait until mouseup before
+		// we trigger the stop event?
+		"mouseleave .ui-spinner-button": "_stop"
+	},
+
+	_draw: function() {
+		var uiSpinner = this.uiSpinner = this.element
+			.addClass( "ui-spinner-input" )
+			.attr( "autocomplete", "off" )
+			.wrap( this._uiSpinnerHtml() )
+			.parent()
+				// add buttons
+				.append( this._buttonHtml() );
+
+		this.element.attr( "role", "spinbutton" );
+
+		// button bindings
+		this.buttons = uiSpinner.find( ".ui-spinner-button" )
+			.attr( "tabIndex", -1 )
+			.button()
+			.removeClass( "ui-corner-all" );
+
+		// IE 6 doesn't understand height: 50% for the buttons
+		// unless the wrapper has an explicit height
+		if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
+				uiSpinner.height() > 0 ) {
+			uiSpinner.height( uiSpinner.height() );
+		}
+
+		// disable spinner if element was already disabled
+		if ( this.options.disabled ) {
+			this.disable();
+		}
+	},
+
+	_keydown: function( event ) {
+		var options = this.options,
+			keyCode = $.ui.keyCode;
+
+		switch ( event.keyCode ) {
+		case keyCode.UP:
+			this._repeat( null, 1, event );
+			return true;
+		case keyCode.DOWN:
+			this._repeat( null, -1, event );
+			return true;
+		case keyCode.PAGE_UP:
+			this._repeat( null, options.page, event );
+			return true;
+		case keyCode.PAGE_DOWN:
+			this._repeat( null, -options.page, event );
+			return true;
+		}
+
+		return false;
+	},
+
+	_uiSpinnerHtml: function() {
+		return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
+	},
+
+	_buttonHtml: function() {
+		return "" +
+			"<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
+				"<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
+			"</a>" +
+			"<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
+				"<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
+			"</a>";
+	},
+
+	_start: function( event ) {
+		if ( !this.spinning && this._trigger( "start", event ) === false ) {
+			return false;
+		}
+
+		if ( !this.counter ) {
+			this.counter = 1;
+		}
+		this.spinning = true;
+		return true;
+	},
+
+	_repeat: function( i, steps, event ) {
+		i = i || 500;
+
+		clearTimeout( this.timer );
+		this.timer = this._delay(function() {
+			this._repeat( 40, steps, event );
+		}, i );
+
+		this._spin( steps * this.options.step, event );
+	},
+
+	_spin: function( step, event ) {
+		var value = this.value() || 0;
+
+		if ( !this.counter ) {
+			this.counter = 1;
+		}
+
+		value = this._adjustValue( value + step * this._increment( this.counter ) );
+
+		if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
+			this._value( value );
+			this.counter++;
+		}
+	},
+
+	_increment: function( i ) {
+		var incremental = this.options.incremental;
+
+		if ( incremental ) {
+			return $.isFunction( incremental ) ?
+				incremental( i ) :
+				Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
+		}
+
+		return 1;
+	},
+
+	_precision: function() {
+		var precision = this._precisionOf( this.options.step );
+		if ( this.options.min !== null ) {
+			precision = Math.max( precision, this._precisionOf( this.options.min ) );
+		}
+		return precision;
+	},
+
+	_precisionOf: function( num ) {
+		var str = num.toString(),
+			decimal = str.indexOf( "." );
+		return decimal === -1 ? 0 : str.length - decimal - 1;
+	},
+
+	_adjustValue: function( value ) {
+		var base, aboveMin,
+			options = this.options;
+
+		// make sure we're at a valid step
+		// - find out where we are relative to the base (min or 0)
+		base = options.min !== null ? options.min : 0;
+		aboveMin = value - base;
+		// - round to the nearest step
+		aboveMin = Math.round(aboveMin / options.step) * options.step;
+		// - rounding is based on 0, so adjust back to our base
+		value = base + aboveMin;
+
+		// fix precision from bad JS floating point math
+		value = parseFloat( value.toFixed( this._precision() ) );
+
+		// clamp the value
+		if ( options.max !== null && value > options.max) {
+			return options.max;
+		}
+		if ( options.min !== null && value < options.min ) {
+			return options.min;
+		}
+
+		return value;
+	},
+
+	_stop: function( event ) {
+		if ( !this.spinning ) {
+			return;
+		}
+
+		clearTimeout( this.timer );
+		clearTimeout( this.mousewheelTimer );
+		this.counter = 0;
+		this.spinning = false;
+		this._trigger( "stop", event );
+	},
+
+	_setOption: function( key, value ) {
+		if ( key === "culture" || key === "numberFormat" ) {
+			var prevValue = this._parse( this.element.val() );
+			this.options[ key ] = value;
+			this.element.val( this._format( prevValue ) );
+			return;
+		}
+
+		if ( key === "max" || key === "min" || key === "step" ) {
+			if ( typeof value === "string" ) {
+				value = this._parse( value );
+			}
+		}
+		if ( key === "icons" ) {
+			this.buttons.first().find( ".ui-icon" )
+				.removeClass( this.options.icons.up )
+				.addClass( value.up );
+			this.buttons.last().find( ".ui-icon" )
+				.removeClass( this.options.icons.down )
+				.addClass( value.down );
+		}
+
+		this._super( key, value );
+
+		if ( key === "disabled" ) {
+			this.widget().toggleClass( "ui-state-disabled", !!value );
+			this.element.prop( "disabled", !!value );
+			this.buttons.button( value ? "disable" : "enable" );
+		}
+	},
+
+	_setOptions: spinner_modifier(function( options ) {
+		this._super( options );
+	}),
+
+	_parse: function( val ) {
+		if ( typeof val === "string" && val !== "" ) {
+			val = window.Globalize && this.options.numberFormat ?
+				Globalize.parseFloat( val, 10, this.options.culture ) : +val;
+		}
+		return val === "" || isNaN( val ) ? null : val;
+	},
+
+	_format: function( value ) {
+		if ( value === "" ) {
+			return "";
+		}
+		return window.Globalize && this.options.numberFormat ?
+			Globalize.format( value, this.options.numberFormat, this.options.culture ) :
+			value;
+	},
+
+	_refresh: function() {
+		this.element.attr({
+			"aria-valuemin": this.options.min,
+			"aria-valuemax": this.options.max,
+			// TODO: what should we do with values that can't be parsed?
+			"aria-valuenow": this._parse( this.element.val() )
+		});
+	},
+
+	isValid: function() {
+		var value = this.value();
+
+		// null is invalid
+		if ( value === null ) {
+			return false;
+		}
+
+		// if value gets adjusted, it's invalid
+		return value === this._adjustValue( value );
+	},
+
+	// update the value without triggering change
+	_value: function( value, allowAny ) {
+		var parsed;
+		if ( value !== "" ) {
+			parsed = this._parse( value );
+			if ( parsed !== null ) {
+				if ( !allowAny ) {
+					parsed = this._adjustValue( parsed );
+				}
+				value = this._format( parsed );
+			}
+		}
+		this.element.val( value );
+		this._refresh();
+	},
+
+	_destroy: function() {
+		this.element
+			.removeClass( "ui-spinner-input" )
+			.prop( "disabled", false )
+			.removeAttr( "autocomplete" )
+			.removeAttr( "role" )
+			.removeAttr( "aria-valuemin" )
+			.removeAttr( "aria-valuemax" )
+			.removeAttr( "aria-valuenow" );
+		this.uiSpinner.replaceWith( this.element );
+	},
+
+	stepUp: spinner_modifier(function( steps ) {
+		this._stepUp( steps );
+	}),
+	_stepUp: function( steps ) {
+		if ( this._start() ) {
+			this._spin( (steps || 1) * this.options.step );
+			this._stop();
+		}
+	},
+
+	stepDown: spinner_modifier(function( steps ) {
+		this._stepDown( steps );
+	}),
+	_stepDown: function( steps ) {
+		if ( this._start() ) {
+			this._spin( (steps || 1) * -this.options.step );
+			this._stop();
+		}
+	},
+
+	pageUp: spinner_modifier(function( pages ) {
+		this._stepUp( (pages || 1) * this.options.page );
+	}),
+
+	pageDown: spinner_modifier(function( pages ) {
+		this._stepDown( (pages || 1) * this.options.page );
+	}),
+
+	value: function( newVal ) {
+		if ( !arguments.length ) {
+			return this._parse( this.element.val() );
+		}
+		spinner_modifier( this._value ).call( this, newVal );
+	},
+
+	widget: function() {
+		return this.uiSpinner;
+	}
+});
+
+
+/*!
+ * jQuery UI Tabs 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/tabs/
+ */
+
+
+var tabs = $.widget( "ui.tabs", {
+	version: "1.11.4",
+	delay: 300,
+	options: {
+		active: null,
+		collapsible: false,
+		event: "click",
+		heightStyle: "content",
+		hide: null,
+		show: null,
+
+		// callbacks
+		activate: null,
+		beforeActivate: null,
+		beforeLoad: null,
+		load: null
+	},
+
+	_isLocal: (function() {
+		var rhash = /#.*$/;
+
+		return function( anchor ) {
+			var anchorUrl, locationUrl;
+
+			// support: IE7
+			// IE7 doesn't normalize the href property when set via script (#9317)
+			anchor = anchor.cloneNode( false );
+
+			anchorUrl = anchor.href.replace( rhash, "" );
+			locationUrl = location.href.replace( rhash, "" );
+
+			// decoding may throw an error if the URL isn't UTF-8 (#9518)
+			try {
+				anchorUrl = decodeURIComponent( anchorUrl );
+			} catch ( error ) {}
+			try {
+				locationUrl = decodeURIComponent( locationUrl );
+			} catch ( error ) {}
+
+			return anchor.hash.length > 1 && anchorUrl === locationUrl;
+		};
+	})(),
+
+	_create: function() {
+		var that = this,
+			options = this.options;
+
+		this.running = false;
+
+		this.element
+			.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
+			.toggleClass( "ui-tabs-collapsible", options.collapsible );
+
+		this._processTabs();
+		options.active = this._initialActive();
+
+		// Take disabling tabs via class attribute from HTML
+		// into account and update option properly.
+		if ( $.isArray( options.disabled ) ) {
+			options.disabled = $.unique( options.disabled.concat(
+				$.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
+					return that.tabs.index( li );
+				})
+			) ).sort();
+		}
+
+		// check for length avoids error when initializing empty list
+		if ( this.options.active !== false && this.anchors.length ) {
+			this.active = this._findActive( options.active );
+		} else {
+			this.active = $();
+		}
+
+		this._refresh();
+
+		if ( this.active.length ) {
+			this.load( options.active );
+		}
+	},
+
+	_initialActive: function() {
+		var active = this.options.active,
+			collapsible = this.options.collapsible,
+			locationHash = location.hash.substring( 1 );
+
+		if ( active === null ) {
+			// check the fragment identifier in the URL
+			if ( locationHash ) {
+				this.tabs.each(function( i, tab ) {
+					if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
+						active = i;
+						return false;
+					}
+				});
+			}
+
+			// check for a tab marked active via a class
+			if ( active === null ) {
+				active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
+			}
+
+			// no active tab, set to false
+			if ( active === null || active === -1 ) {
+				active = this.tabs.length ? 0 : false;
+			}
+		}
+
+		// handle numbers: negative, out of range
+		if ( active !== false ) {
+			active = this.tabs.index( this.tabs.eq( active ) );
+			if ( active === -1 ) {
+				active = collapsible ? false : 0;
+			}
+		}
+
+		// don't allow collapsible: false and active: false
+		if ( !collapsible && active === false && this.anchors.length ) {
+			active = 0;
+		}
+
+		return active;
+	},
+
+	_getCreateEventData: function() {
+		return {
+			tab: this.active,
+			panel: !this.active.length ? $() : this._getPanelForTab( this.active )
+		};
+	},
+
+	_tabKeydown: function( event ) {
+		var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
+			selectedIndex = this.tabs.index( focusedTab ),
+			goingForward = true;
+
+		if ( this._handlePageNav( event ) ) {
+			return;
+		}
+
+		switch ( event.keyCode ) {
+			case $.ui.keyCode.RIGHT:
+			case $.ui.keyCode.DOWN:
+				selectedIndex++;
+				break;
+			case $.ui.keyCode.UP:
+			case $.ui.keyCode.LEFT:
+				goingForward = false;
+				selectedIndex--;
+				break;
+			case $.ui.keyCode.END:
+				selectedIndex = this.anchors.length - 1;
+				break;
+			case $.ui.keyCode.HOME:
+				selectedIndex = 0;
+				break;
+			case $.ui.keyCode.SPACE:
+				// Activate only, no collapsing
+				event.preventDefault();
+				clearTimeout( this.activating );
+				this._activate( selectedIndex );
+				return;
+			case $.ui.keyCode.ENTER:
+				// Toggle (cancel delayed activation, allow collapsing)
+				event.preventDefault();
+				clearTimeout( this.activating );
+				// Determine if we should collapse or activate
+				this._activate( selectedIndex === this.options.active ? false : selectedIndex );
+				return;
+			default:
+				return;
+		}
+
+		// Focus the appropriate tab, based on which key was pressed
+		event.preventDefault();
+		clearTimeout( this.activating );
+		selectedIndex = this._focusNextTab( selectedIndex, goingForward );
+
+		// Navigating with control/command key will prevent automatic activation
+		if ( !event.ctrlKey && !event.metaKey ) {
+
+			// Update aria-selected immediately so that AT think the tab is already selected.
+			// Otherwise AT may confuse the user by stating that they need to activate the tab,
+			// but the tab will already be activated by the time the announcement finishes.
+			focusedTab.attr( "aria-selected", "false" );
+			this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
+
+			this.activating = this._delay(function() {
+				this.option( "active", selectedIndex );
+			}, this.delay );
+		}
+	},
+
+	_panelKeydown: function( event ) {
+		if ( this._handlePageNav( event ) ) {
+			return;
+		}
+
+		// Ctrl+up moves focus to the current tab
+		if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
+			event.preventDefault();
+			this.active.focus();
+		}
+	},
+
+	// Alt+page up/down moves focus to the previous/next tab (and activates)
+	_handlePageNav: function( event ) {
+		if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
+			this._activate( this._focusNextTab( this.options.active - 1, false ) );
+			return true;
+		}
+		if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
+			this._activate( this._focusNextTab( this.options.active + 1, true ) );
+			return true;
+		}
+	},
+
+	_findNextTab: function( index, goingForward ) {
+		var lastTabIndex = this.tabs.length - 1;
+
+		function constrain() {
+			if ( index > lastTabIndex ) {
+				index = 0;
+			}
+			if ( index < 0 ) {
+				index = lastTabIndex;
+			}
+			return index;
+		}
+
+		while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
+			index = goingForward ? index + 1 : index - 1;
+		}
+
+		return index;
+	},
+
+	_focusNextTab: function( index, goingForward ) {
+		index = this._findNextTab( index, goingForward );
+		this.tabs.eq( index ).focus();
+		return index;
+	},
+
+	_setOption: function( key, value ) {
+		if ( key === "active" ) {
+			// _activate() will handle invalid values and update this.options
+			this._activate( value );
+			return;
+		}
+
+		if ( key === "disabled" ) {
+			// don't use the widget factory's disabled handling
+			this._setupDisabled( value );
+			return;
+		}
+
+		this._super( key, value);
+
+		if ( key === "collapsible" ) {
+			this.element.toggleClass( "ui-tabs-collapsible", value );
+			// Setting collapsible: false while collapsed; open first panel
+			if ( !value && this.options.active === false ) {
+				this._activate( 0 );
+			}
+		}
+
+		if ( key === "event" ) {
+			this._setupEvents( value );
+		}
+
+		if ( key === "heightStyle" ) {
+			this._setupHeightStyle( value );
+		}
+	},
+
+	_sanitizeSelector: function( hash ) {
+		return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
+	},
+
+	refresh: function() {
+		var options = this.options,
+			lis = this.tablist.children( ":has(a[href])" );
+
+		// get disabled tabs from class attribute from HTML
+		// this will get converted to a boolean if needed in _refresh()
+		options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
+			return lis.index( tab );
+		});
+
+		this._processTabs();
+
+		// was collapsed or no tabs
+		if ( options.active === false || !this.anchors.length ) {
+			options.active = false;
+			this.active = $();
+		// was active, but active tab is gone
+		} else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
+			// all remaining tabs are disabled
+			if ( this.tabs.length === options.disabled.length ) {
+				options.active = false;
+				this.active = $();
+			// activate previous tab
+			} else {
+				this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
+			}
+		// was active, active tab still exists
+		} else {
+			// make sure active index is correct
+			options.active = this.tabs.index( this.active );
+		}
+
+		this._refresh();
+	},
+
+	_refresh: function() {
+		this._setupDisabled( this.options.disabled );
+		this._setupEvents( this.options.event );
+		this._setupHeightStyle( this.options.heightStyle );
+
+		this.tabs.not( this.active ).attr({
+			"aria-selected": "false",
+			"aria-expanded": "false",
+			tabIndex: -1
+		});
+		this.panels.not( this._getPanelForTab( this.active ) )
+			.hide()
+			.attr({
+				"aria-hidden": "true"
+			});
+
+		// Make sure one tab is in the tab order
+		if ( !this.active.length ) {
+			this.tabs.eq( 0 ).attr( "tabIndex", 0 );
+		} else {
+			this.active
+				.addClass( "ui-tabs-active ui-state-active" )
+				.attr({
+					"aria-selected": "true",
+					"aria-expanded": "true",
+					tabIndex: 0
+				});
+			this._getPanelForTab( this.active )
+				.show()
+				.attr({
+					"aria-hidden": "false"
+				});
+		}
+	},
+
+	_processTabs: function() {
+		var that = this,
+			prevTabs = this.tabs,
+			prevAnchors = this.anchors,
+			prevPanels = this.panels;
+
+		this.tablist = this._getList()
+			.addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
+			.attr( "role", "tablist" )
+
+			// Prevent users from focusing disabled tabs via click
+			.delegate( "> li", "mousedown" + this.eventNamespace, function( event ) {
+				if ( $( this ).is( ".ui-state-disabled" ) ) {
+					event.preventDefault();
+				}
+			})
+
+			// support: IE <9
+			// Preventing the default action in mousedown doesn't prevent IE
+			// from focusing the element, so if the anchor gets focused, blur.
+			// We don't have to worry about focusing the previously focused
+			// element since clicking on a non-focusable element should focus
+			// the body anyway.
+			.delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
+				if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
+					this.blur();
+				}
+			});
+
+		this.tabs = this.tablist.find( "> li:has(a[href])" )
+			.addClass( "ui-state-default ui-corner-top" )
+			.attr({
+				role: "tab",
+				tabIndex: -1
+			});
+
+		this.anchors = this.tabs.map(function() {
+				return $( "a", this )[ 0 ];
+			})
+			.addClass( "ui-tabs-anchor" )
+			.attr({
+				role: "presentation",
+				tabIndex: -1
+			});
+
+		this.panels = $();
+
+		this.anchors.each(function( i, anchor ) {
+			var selector, panel, panelId,
+				anchorId = $( anchor ).uniqueId().attr( "id" ),
+				tab = $( anchor ).closest( "li" ),
+				originalAriaControls = tab.attr( "aria-controls" );
+
+			// inline tab
+			if ( that._isLocal( anchor ) ) {
+				selector = anchor.hash;
+				panelId = selector.substring( 1 );
+				panel = that.element.find( that._sanitizeSelector( selector ) );
+			// remote tab
+			} else {
+				// If the tab doesn't already have aria-controls,
+				// generate an id by using a throw-away element
+				panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
+				selector = "#" + panelId;
+				panel = that.element.find( selector );
+				if ( !panel.length ) {
+					panel = that._createPanel( panelId );
+					panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
+				}
+				panel.attr( "aria-live", "polite" );
+			}
+
+			if ( panel.length) {
+				that.panels = that.panels.add( panel );
+			}
+			if ( originalAriaControls ) {
+				tab.data( "ui-tabs-aria-controls", originalAriaControls );
+			}
+			tab.attr({
+				"aria-controls": panelId,
+				"aria-labelledby": anchorId
+			});
+			panel.attr( "aria-labelledby", anchorId );
+		});
+
+		this.panels
+			.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
+			.attr( "role", "tabpanel" );
+
+		// Avoid memory leaks (#10056)
+		if ( prevTabs ) {
+			this._off( prevTabs.not( this.tabs ) );
+			this._off( prevAnchors.not( this.anchors ) );
+			this._off( prevPanels.not( this.panels ) );
+		}
+	},
+
+	// allow overriding how to find the list for rare usage scenarios (#7715)
+	_getList: function() {
+		return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
+	},
+
+	_createPanel: function( id ) {
+		return $( "<div>" )
+			.attr( "id", id )
+			.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
+			.data( "ui-tabs-destroy", true );
+	},
+
+	_setupDisabled: function( disabled ) {
+		if ( $.isArray( disabled ) ) {
+			if ( !disabled.length ) {
+				disabled = false;
+			} else if ( disabled.length === this.anchors.length ) {
+				disabled = true;
+			}
+		}
+
+		// disable tabs
+		for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
+			if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
+				$( li )
+					.addClass( "ui-state-disabled" )
+					.attr( "aria-disabled", "true" );
+			} else {
+				$( li )
+					.removeClass( "ui-state-disabled" )
+					.removeAttr( "aria-disabled" );
+			}
+		}
+
+		this.options.disabled = disabled;
+	},
+
+	_setupEvents: function( event ) {
+		var events = {};
+		if ( event ) {
+			$.each( event.split(" "), function( index, eventName ) {
+				events[ eventName ] = "_eventHandler";
+			});
+		}
+
+		this._off( this.anchors.add( this.tabs ).add( this.panels ) );
+		// Always prevent the default action, even when disabled
+		this._on( true, this.anchors, {
+			click: function( event ) {
+				event.preventDefault();
+			}
+		});
+		this._on( this.anchors, events );
+		this._on( this.tabs, { keydown: "_tabKeydown" } );
+		this._on( this.panels, { keydown: "_panelKeydown" } );
+
+		this._focusable( this.tabs );
+		this._hoverable( this.tabs );
+	},
+
+	_setupHeightStyle: function( heightStyle ) {
+		var maxHeight,
+			parent = this.element.parent();
+
+		if ( heightStyle === "fill" ) {
+			maxHeight = parent.height();
+			maxHeight -= this.element.outerHeight() - this.element.height();
+
+			this.element.siblings( ":visible" ).each(function() {
+				var elem = $( this ),
+					position = elem.css( "position" );
+
+				if ( position === "absolute" || position === "fixed" ) {
+					return;
+				}
+				maxHeight -= elem.outerHeight( true );
+			});
+
+			this.element.children().not( this.panels ).each(function() {
+				maxHeight -= $( this ).outerHeight( true );
+			});
+
+			this.panels.each(function() {
+				$( this ).height( Math.max( 0, maxHeight -
+					$( this ).innerHeight() + $( this ).height() ) );
+			})
+			.css( "overflow", "auto" );
+		} else if ( heightStyle === "auto" ) {
+			maxHeight = 0;
+			this.panels.each(function() {
+				maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
+			}).height( maxHeight );
+		}
+	},
+
+	_eventHandler: function( event ) {
+		var options = this.options,
+			active = this.active,
+			anchor = $( event.currentTarget ),
+			tab = anchor.closest( "li" ),
+			clickedIsActive = tab[ 0 ] === active[ 0 ],
+			collapsing = clickedIsActive && options.collapsible,
+			toShow = collapsing ? $() : this._getPanelForTab( tab ),
+			toHide = !active.length ? $() : this._getPanelForTab( active ),
+			eventData = {
+				oldTab: active,
+				oldPanel: toHide,
+				newTab: collapsing ? $() : tab,
+				newPanel: toShow
+			};
+
+		event.preventDefault();
+
+		if ( tab.hasClass( "ui-state-disabled" ) ||
+				// tab is already loading
+				tab.hasClass( "ui-tabs-loading" ) ||
+				// can't switch durning an animation
+				this.running ||
+				// click on active header, but not collapsible
+				( clickedIsActive && !options.collapsible ) ||
+				// allow canceling activation
+				( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+			return;
+		}
+
+		options.active = collapsing ? false : this.tabs.index( tab );
+
+		this.active = clickedIsActive ? $() : tab;
+		if ( this.xhr ) {
+			this.xhr.abort();
+		}
+
+		if ( !toHide.length && !toShow.length ) {
+			$.error( "jQuery UI Tabs: Mismatching fragment identifier." );
+		}
+
+		if ( toShow.length ) {
+			this.load( this.tabs.index( tab ), event );
+		}
+		this._toggle( event, eventData );
+	},
+
+	// handles show/hide for selecting tabs
+	_toggle: function( event, eventData ) {
+		var that = this,
+			toShow = eventData.newPanel,
+			toHide = eventData.oldPanel;
+
+		this.running = true;
+
+		function complete() {
+			that.running = false;
+			that._trigger( "activate", event, eventData );
+		}
+
+		function show() {
+			eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
+
+			if ( toShow.length && that.options.show ) {
+				that._show( toShow, that.options.show, complete );
+			} else {
+				toShow.show();
+				complete();
+			}
+		}
+
+		// start out by hiding, then showing, then completing
+		if ( toHide.length && this.options.hide ) {
+			this._hide( toHide, this.options.hide, function() {
+				eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
+				show();
+			});
+		} else {
+			eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
+			toHide.hide();
+			show();
+		}
+
+		toHide.attr( "aria-hidden", "true" );
+		eventData.oldTab.attr({
+			"aria-selected": "false",
+			"aria-expanded": "false"
+		});
+		// If we're switching tabs, remove the old tab from the tab order.
+		// If we're opening from collapsed state, remove the previous tab from the tab order.
+		// If we're collapsing, then keep the collapsing tab in the tab order.
+		if ( toShow.length && toHide.length ) {
+			eventData.oldTab.attr( "tabIndex", -1 );
+		} else if ( toShow.length ) {
+			this.tabs.filter(function() {
+				return $( this ).attr( "tabIndex" ) === 0;
+			})
+			.attr( "tabIndex", -1 );
+		}
+
+		toShow.attr( "aria-hidden", "false" );
+		eventData.newTab.attr({
+			"aria-selected": "true",
+			"aria-expanded": "true",
+			tabIndex: 0
+		});
+	},
+
+	_activate: function( index ) {
+		var anchor,
+			active = this._findActive( index );
+
+		// trying to activate the already active panel
+		if ( active[ 0 ] === this.active[ 0 ] ) {
+			return;
+		}
+
+		// trying to collapse, simulate a click on the current active header
+		if ( !active.length ) {
+			active = this.active;
+		}
+
+		anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
+		this._eventHandler({
+			target: anchor,
+			currentTarget: anchor,
+			preventDefault: $.noop
+		});
+	},
+
+	_findActive: function( index ) {
+		return index === false ? $() : this.tabs.eq( index );
+	},
+
+	_getIndex: function( index ) {
+		// meta-function to give users option to provide a href string instead of a numerical index.
+		if ( typeof index === "string" ) {
+			index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
+		}
+
+		return index;
+	},
+
+	_destroy: function() {
+		if ( this.xhr ) {
+			this.xhr.abort();
+		}
+
+		this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
+
+		this.tablist
+			.removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
+			.removeAttr( "role" );
+
+		this.anchors
+			.removeClass( "ui-tabs-anchor" )
+			.removeAttr( "role" )
+			.removeAttr( "tabIndex" )
+			.removeUniqueId();
+
+		this.tablist.unbind( this.eventNamespace );
+
+		this.tabs.add( this.panels ).each(function() {
+			if ( $.data( this, "ui-tabs-destroy" ) ) {
+				$( this ).remove();
+			} else {
+				$( this )
+					.removeClass( "ui-state-default ui-state-active ui-state-disabled " +
+						"ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
+					.removeAttr( "tabIndex" )
+					.removeAttr( "aria-live" )
+					.removeAttr( "aria-busy" )
+					.removeAttr( "aria-selected" )
+					.removeAttr( "aria-labelledby" )
+					.removeAttr( "aria-hidden" )
+					.removeAttr( "aria-expanded" )
+					.removeAttr( "role" );
+			}
+		});
+
+		this.tabs.each(function() {
+			var li = $( this ),
+				prev = li.data( "ui-tabs-aria-controls" );
+			if ( prev ) {
+				li
+					.attr( "aria-controls", prev )
+					.removeData( "ui-tabs-aria-controls" );
+			} else {
+				li.removeAttr( "aria-controls" );
+			}
+		});
+
+		this.panels.show();
+
+		if ( this.options.heightStyle !== "content" ) {
+			this.panels.css( "height", "" );
+		}
+	},
+
+	enable: function( index ) {
+		var disabled = this.options.disabled;
+		if ( disabled === false ) {
+			return;
+		}
+
+		if ( index === undefined ) {
+			disabled = false;
+		} else {
+			index = this._getIndex( index );
+			if ( $.isArray( disabled ) ) {
+				disabled = $.map( disabled, function( num ) {
+					return num !== index ? num : null;
+				});
+			} else {
+				disabled = $.map( this.tabs, function( li, num ) {
+					return num !== index ? num : null;
+				});
+			}
+		}
+		this._setupDisabled( disabled );
+	},
+
+	disable: function( index ) {
+		var disabled = this.options.disabled;
+		if ( disabled === true ) {
+			return;
+		}
+
+		if ( index === undefined ) {
+			disabled = true;
+		} else {
+			index = this._getIndex( index );
+			if ( $.inArray( index, disabled ) !== -1 ) {
+				return;
+			}
+			if ( $.isArray( disabled ) ) {
+				disabled = $.merge( [ index ], disabled ).sort();
+			} else {
+				disabled = [ index ];
+			}
+		}
+		this._setupDisabled( disabled );
+	},
+
+	load: function( index, event ) {
+		index = this._getIndex( index );
+		var that = this,
+			tab = this.tabs.eq( index ),
+			anchor = tab.find( ".ui-tabs-anchor" ),
+			panel = this._getPanelForTab( tab ),
+			eventData = {
+				tab: tab,
+				panel: panel
+			},
+			complete = function( jqXHR, status ) {
+				if ( status === "abort" ) {
+					that.panels.stop( false, true );
+				}
+
+				tab.removeClass( "ui-tabs-loading" );
+				panel.removeAttr( "aria-busy" );
+
+				if ( jqXHR === that.xhr ) {
+					delete that.xhr;
+				}
+			};
+
+		// not remote
+		if ( this._isLocal( anchor[ 0 ] ) ) {
+			return;
+		}
+
+		this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
+
+		// support: jQuery <1.8
+		// jQuery <1.8 returns false if the request is canceled in beforeSend,
+		// but as of 1.8, $.ajax() always returns a jqXHR object.
+		if ( this.xhr && this.xhr.statusText !== "canceled" ) {
+			tab.addClass( "ui-tabs-loading" );
+			panel.attr( "aria-busy", "true" );
+
+			this.xhr
+				.done(function( response, status, jqXHR ) {
+					// support: jQuery <1.8
+					// http://bugs.jquery.com/ticket/11778
+					setTimeout(function() {
+						panel.html( response );
+						that._trigger( "load", event, eventData );
+
+						complete( jqXHR, status );
+					}, 1 );
+				})
+				.fail(function( jqXHR, status ) {
+					// support: jQuery <1.8
+					// http://bugs.jquery.com/ticket/11778
+					setTimeout(function() {
+						complete( jqXHR, status );
+					}, 1 );
+				});
+		}
+	},
+
+	_ajaxSettings: function( anchor, event, eventData ) {
+		var that = this;
+		return {
+			url: anchor.attr( "href" ),
+			beforeSend: function( jqXHR, settings ) {
+				return that._trigger( "beforeLoad", event,
+					$.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
+			}
+		};
+	},
+
+	_getPanelForTab: function( tab ) {
+		var id = $( tab ).attr( "aria-controls" );
+		return this.element.find( this._sanitizeSelector( "#" + id ) );
+	}
+});
+
+
+/*!
+ * jQuery UI Tooltip 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/tooltip/
+ */
+
+
+var tooltip = $.widget( "ui.tooltip", {
+	version: "1.11.4",
+	options: {
+		content: function() {
+			// support: IE<9, Opera in jQuery <1.7
+			// .text() can't accept undefined, so coerce to a string
+			var title = $( this ).attr( "title" ) || "";
+			// Escape title, since we're going from an attribute to raw HTML
+			return $( "<a>" ).text( title ).html();
+		},
+		hide: true,
+		// Disabled elements have inconsistent behavior across browsers (#8661)
+		items: "[title]:not([disabled])",
+		position: {
+			my: "left top+15",
+			at: "left bottom",
+			collision: "flipfit flip"
+		},
+		show: true,
+		tooltipClass: null,
+		track: false,
+
+		// callbacks
+		close: null,
+		open: null
+	},
+
+	_addDescribedBy: function( elem, id ) {
+		var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
+		describedby.push( id );
+		elem
+			.data( "ui-tooltip-id", id )
+			.attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
+	},
+
+	_removeDescribedBy: function( elem ) {
+		var id = elem.data( "ui-tooltip-id" ),
+			describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
+			index = $.inArray( id, describedby );
+
+		if ( index !== -1 ) {
+			describedby.splice( index, 1 );
+		}
+
+		elem.removeData( "ui-tooltip-id" );
+		describedby = $.trim( describedby.join( " " ) );
+		if ( describedby ) {
+			elem.attr( "aria-describedby", describedby );
+		} else {
+			elem.removeAttr( "aria-describedby" );
+		}
+	},
+
+	_create: function() {
+		this._on({
+			mouseover: "open",
+			focusin: "open"
+		});
+
+		// IDs of generated tooltips, needed for destroy
+		this.tooltips = {};
+
+		// IDs of parent tooltips where we removed the title attribute
+		this.parents = {};
+
+		if ( this.options.disabled ) {
+			this._disable();
+		}
+
+		// Append the aria-live region so tooltips announce correctly
+		this.liveRegion = $( "<div>" )
+			.attr({
+				role: "log",
+				"aria-live": "assertive",
+				"aria-relevant": "additions"
+			})
+			.addClass( "ui-helper-hidden-accessible" )
+			.appendTo( this.document[ 0 ].body );
+	},
+
+	_setOption: function( key, value ) {
+		var that = this;
+
+		if ( key === "disabled" ) {
+			this[ value ? "_disable" : "_enable" ]();
+			this.options[ key ] = value;
+			// disable element style changes
+			return;
+		}
+
+		this._super( key, value );
+
+		if ( key === "content" ) {
+			$.each( this.tooltips, function( id, tooltipData ) {
+				that._updateContent( tooltipData.element );
+			});
+		}
+	},
+
+	_disable: function() {
+		var that = this;
+
+		// close open tooltips
+		$.each( this.tooltips, function( id, tooltipData ) {
+			var event = $.Event( "blur" );
+			event.target = event.currentTarget = tooltipData.element[ 0 ];
+			that.close( event, true );
+		});
+
+		// remove title attributes to prevent native tooltips
+		this.element.find( this.options.items ).addBack().each(function() {
+			var element = $( this );
+			if ( element.is( "[title]" ) ) {
+				element
+					.data( "ui-tooltip-title", element.attr( "title" ) )
+					.removeAttr( "title" );
+			}
+		});
+	},
+
+	_enable: function() {
+		// restore title attributes
+		this.element.find( this.options.items ).addBack().each(function() {
+			var element = $( this );
+			if ( element.data( "ui-tooltip-title" ) ) {
+				element.attr( "title", element.data( "ui-tooltip-title" ) );
+			}
+		});
+	},
+
+	open: function( event ) {
+		var that = this,
+			target = $( event ? event.target : this.element )
+				// we need closest here due to mouseover bubbling,
+				// but always pointing at the same event target
+				.closest( this.options.items );
+
+		// No element to show a tooltip for or the tooltip is already open
+		if ( !target.length || target.data( "ui-tooltip-id" ) ) {
+			return;
+		}
+
+		if ( target.attr( "title" ) ) {
+			target.data( "ui-tooltip-title", target.attr( "title" ) );
+		}
+
+		target.data( "ui-tooltip-open", true );
+
+		// kill parent tooltips, custom or native, for hover
+		if ( event && event.type === "mouseover" ) {
+			target.parents().each(function() {
+				var parent = $( this ),
+					blurEvent;
+				if ( parent.data( "ui-tooltip-open" ) ) {
+					blurEvent = $.Event( "blur" );
+					blurEvent.target = blurEvent.currentTarget = this;
+					that.close( blurEvent, true );
+				}
+				if ( parent.attr( "title" ) ) {
+					parent.uniqueId();
+					that.parents[ this.id ] = {
+						element: this,
+						title: parent.attr( "title" )
+					};
+					parent.attr( "title", "" );
+				}
+			});
+		}
+
+		this._registerCloseHandlers( event, target );
+		this._updateContent( target, event );
+	},
+
+	_updateContent: function( target, event ) {
+		var content,
+			contentOption = this.options.content,
+			that = this,
+			eventType = event ? event.type : null;
+
+		if ( typeof contentOption === "string" ) {
+			return this._open( event, target, contentOption );
+		}
+
+		content = contentOption.call( target[0], function( response ) {
+
+			// IE may instantly serve a cached response for ajax requests
+			// delay this call to _open so the other call to _open runs first
+			that._delay(function() {
+
+				// Ignore async response if tooltip was closed already
+				if ( !target.data( "ui-tooltip-open" ) ) {
+					return;
+				}
+
+				// jQuery creates a special event for focusin when it doesn't
+				// exist natively. To improve performance, the native event
+				// object is reused and the type is changed. Therefore, we can't
+				// rely on the type being correct after the event finished
+				// bubbling, so we set it back to the previous value. (#8740)
+				if ( event ) {
+					event.type = eventType;
+				}
+				this._open( event, target, response );
+			});
+		});
+		if ( content ) {
+			this._open( event, target, content );
+		}
+	},
+
+	_open: function( event, target, content ) {
+		var tooltipData, tooltip, delayedShow, a11yContent,
+			positionOption = $.extend( {}, this.options.position );
+
+		if ( !content ) {
+			return;
+		}
+
+		// Content can be updated multiple times. If the tooltip already
+		// exists, then just update the content and bail.
+		tooltipData = this._find( target );
+		if ( tooltipData ) {
+			tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
+			return;
+		}
+
+		// if we have a title, clear it to prevent the native tooltip
+		// we have to check first to avoid defining a title if none exists
+		// (we don't want to cause an element to start matching [title])
+		//
+		// We use removeAttr only for key events, to allow IE to export the correct
+		// accessible attributes. For mouse events, set to empty string to avoid
+		// native tooltip showing up (happens only when removing inside mouseover).
+		if ( target.is( "[title]" ) ) {
+			if ( event && event.type === "mouseover" ) {
+				target.attr( "title", "" );
+			} else {
+				target.removeAttr( "title" );
+			}
+		}
+
+		tooltipData = this._tooltip( target );
+		tooltip = tooltipData.tooltip;
+		this._addDescribedBy( target, tooltip.attr( "id" ) );
+		tooltip.find( ".ui-tooltip-content" ).html( content );
+
+		// Support: Voiceover on OS X, JAWS on IE <= 9
+		// JAWS announces deletions even when aria-relevant="additions"
+		// Voiceover will sometimes re-read the entire log region's contents from the beginning
+		this.liveRegion.children().hide();
+		if ( content.clone ) {
+			a11yContent = content.clone();
+			a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
+		} else {
+			a11yContent = content;
+		}
+		$( "<div>" ).html( a11yContent ).appendTo( this.liveRegion );
+
+		function position( event ) {
+			positionOption.of = event;
+			if ( tooltip.is( ":hidden" ) ) {
+				return;
+			}
+			tooltip.position( positionOption );
+		}
+		if ( this.options.track && event && /^mouse/.test( event.type ) ) {
+			this._on( this.document, {
+				mousemove: position
+			});
+			// trigger once to override element-relative positioning
+			position( event );
+		} else {
+			tooltip.position( $.extend({
+				of: target
+			}, this.options.position ) );
+		}
+
+		tooltip.hide();
+
+		this._show( tooltip, this.options.show );
+		// Handle tracking tooltips that are shown with a delay (#8644). As soon
+		// as the tooltip is visible, position the tooltip using the most recent
+		// event.
+		if ( this.options.show && this.options.show.delay ) {
+			delayedShow = this.delayedShow = setInterval(function() {
+				if ( tooltip.is( ":visible" ) ) {
+					position( positionOption.of );
+					clearInterval( delayedShow );
+				}
+			}, $.fx.interval );
+		}
+
+		this._trigger( "open", event, { tooltip: tooltip } );
+	},
+
+	_registerCloseHandlers: function( event, target ) {
+		var events = {
+			keyup: function( event ) {
+				if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
+					var fakeEvent = $.Event(event);
+					fakeEvent.currentTarget = target[0];
+					this.close( fakeEvent, true );
+				}
+			}
+		};
+
+		// Only bind remove handler for delegated targets. Non-delegated
+		// tooltips will handle this in destroy.
+		if ( target[ 0 ] !== this.element[ 0 ] ) {
+			events.remove = function() {
+				this._removeTooltip( this._find( target ).tooltip );
+			};
+		}
+
+		if ( !event || event.type === "mouseover" ) {
+			events.mouseleave = "close";
+		}
+		if ( !event || event.type === "focusin" ) {
+			events.focusout = "close";
+		}
+		this._on( true, target, events );
+	},
+
+	close: function( event ) {
+		var tooltip,
+			that = this,
+			target = $( event ? event.currentTarget : this.element ),
+			tooltipData = this._find( target );
+
+		// The tooltip may already be closed
+		if ( !tooltipData ) {
+
+			// We set ui-tooltip-open immediately upon open (in open()), but only set the
+			// additional data once there's actually content to show (in _open()). So even if the
+			// tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
+			// the period between open() and _open().
+			target.removeData( "ui-tooltip-open" );
+			return;
+		}
+
+		tooltip = tooltipData.tooltip;
+
+		// disabling closes the tooltip, so we need to track when we're closing
+		// to avoid an infinite loop in case the tooltip becomes disabled on close
+		if ( tooltipData.closing ) {
+			return;
+		}
+
+		// Clear the interval for delayed tracking tooltips
+		clearInterval( this.delayedShow );
+
+		// only set title if we had one before (see comment in _open())
+		// If the title attribute has changed since open(), don't restore
+		if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
+			target.attr( "title", target.data( "ui-tooltip-title" ) );
+		}
+
+		this._removeDescribedBy( target );
+
+		tooltipData.hiding = true;
+		tooltip.stop( true );
+		this._hide( tooltip, this.options.hide, function() {
+			that._removeTooltip( $( this ) );
+		});
+
+		target.removeData( "ui-tooltip-open" );
+		this._off( target, "mouseleave focusout keyup" );
+
+		// Remove 'remove' binding only on delegated targets
+		if ( target[ 0 ] !== this.element[ 0 ] ) {
+			this._off( target, "remove" );
+		}
+		this._off( this.document, "mousemove" );
+
+		if ( event && event.type === "mouseleave" ) {
+			$.each( this.parents, function( id, parent ) {
+				$( parent.element ).attr( "title", parent.title );
+				delete that.parents[ id ];
+			});
+		}
+
+		tooltipData.closing = true;
+		this._trigger( "close", event, { tooltip: tooltip } );
+		if ( !tooltipData.hiding ) {
+			tooltipData.closing = false;
+		}
+	},
+
+	_tooltip: function( element ) {
+		var tooltip = $( "<div>" )
+				.attr( "role", "tooltip" )
+				.addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
+					( this.options.tooltipClass || "" ) ),
+			id = tooltip.uniqueId().attr( "id" );
+
+		$( "<div>" )
+			.addClass( "ui-tooltip-content" )
+			.appendTo( tooltip );
+
+		tooltip.appendTo( this.document[0].body );
+
+		return this.tooltips[ id ] = {
+			element: element,
+			tooltip: tooltip
+		};
+	},
+
+	_find: function( target ) {
+		var id = target.data( "ui-tooltip-id" );
+		return id ? this.tooltips[ id ] : null;
+	},
+
+	_removeTooltip: function( tooltip ) {
+		tooltip.remove();
+		delete this.tooltips[ tooltip.attr( "id" ) ];
+	},
+
+	_destroy: function() {
+		var that = this;
+
+		// close open tooltips
+		$.each( this.tooltips, function( id, tooltipData ) {
+			// Delegate to close method to handle common cleanup
+			var event = $.Event( "blur" ),
+				element = tooltipData.element;
+			event.target = event.currentTarget = element[ 0 ];
+			that.close( event, true );
+
+			// Remove immediately; destroying an open tooltip doesn't use the
+			// hide animation
+			$( "#" + id ).remove();
+
+			// Restore the title
+			if ( element.data( "ui-tooltip-title" ) ) {
+				// If the title attribute has changed since open(), don't restore
+				if ( !element.attr( "title" ) ) {
+					element.attr( "title", element.data( "ui-tooltip-title" ) );
+				}
+				element.removeData( "ui-tooltip-title" );
+			}
+		});
+		this.liveRegion.remove();
+	}
+});
+
+
+/*!
+ * jQuery UI Effects 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/effects-core/
+ */
+
+
+var dataSpace = "ui-effects-",
+
+	// Create a local jQuery because jQuery Color relies on it and the
+	// global may not exist with AMD and a custom build (#10199)
+	jQuery = $;
+
+$.effects = {
+	effect: {}
+};
+
+/*!
+ * jQuery Color Animations v2.1.2
+ * https://github.com/jquery/jquery-color
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * Date: Wed Jan 16 08:47:09 2013 -0600
+ */
+(function( jQuery, undefined ) {
+
+	var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
+
+	// plusequals test for += 100 -= 100
+	rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
+	// a set of RE's that can match strings and generate color tuples.
+	stringParsers = [ {
+			re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+			parse: function( execResult ) {
+				return [
+					execResult[ 1 ],
+					execResult[ 2 ],
+					execResult[ 3 ],
+					execResult[ 4 ]
+				];
+			}
+		}, {
+			re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+			parse: function( execResult ) {
+				return [
+					execResult[ 1 ] * 2.55,
+					execResult[ 2 ] * 2.55,
+					execResult[ 3 ] * 2.55,
+					execResult[ 4 ]
+				];
+			}
+		}, {
+			// this regex ignores A-F because it's compared against an already lowercased string
+			re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
+			parse: function( execResult ) {
+				return [
+					parseInt( execResult[ 1 ], 16 ),
+					parseInt( execResult[ 2 ], 16 ),
+					parseInt( execResult[ 3 ], 16 )
+				];
+			}
+		}, {
+			// this regex ignores A-F because it's compared against an already lowercased string
+			re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
+			parse: function( execResult ) {
+				return [
+					parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
+					parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
+					parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
+				];
+			}
+		}, {
+			re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+			space: "hsla",
+			parse: function( execResult ) {
+				return [
+					execResult[ 1 ],
+					execResult[ 2 ] / 100,
+					execResult[ 3 ] / 100,
+					execResult[ 4 ]
+				];
+			}
+		} ],
+
+	// jQuery.Color( )
+	color = jQuery.Color = function( color, green, blue, alpha ) {
+		return new jQuery.Color.fn.parse( color, green, blue, alpha );
+	},
+	spaces = {
+		rgba: {
+			props: {
+				red: {
+					idx: 0,
+					type: "byte"
+				},
+				green: {
+					idx: 1,
+					type: "byte"
+				},
+				blue: {
+					idx: 2,
+					type: "byte"
+				}
+			}
+		},
+
+		hsla: {
+			props: {
+				hue: {
+					idx: 0,
+					type: "degrees"
+				},
+				saturation: {
+					idx: 1,
+					type: "percent"
+				},
+				lightness: {
+					idx: 2,
+					type: "percent"
+				}
+			}
+		}
+	},
+	propTypes = {
+		"byte": {
+			floor: true,
+			max: 255
+		},
+		"percent": {
+			max: 1
+		},
+		"degrees": {
+			mod: 360,
+			floor: true
+		}
+	},
+	support = color.support = {},
+
+	// element for support tests
+	supportElem = jQuery( "<p>" )[ 0 ],
+
+	// colors = jQuery.Color.names
+	colors,
+
+	// local aliases of functions called often
+	each = jQuery.each;
+
+// determine rgba support immediately
+supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
+support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
+
+// define cache name and alpha properties
+// for rgba and hsla spaces
+each( spaces, function( spaceName, space ) {
+	space.cache = "_" + spaceName;
+	space.props.alpha = {
+		idx: 3,
+		type: "percent",
+		def: 1
+	};
+});
+
+function clamp( value, prop, allowEmpty ) {
+	var type = propTypes[ prop.type ] || {};
+
+	if ( value == null ) {
+		return (allowEmpty || !prop.def) ? null : prop.def;
+	}
+
+	// ~~ is an short way of doing floor for positive numbers
+	value = type.floor ? ~~value : parseFloat( value );
+
+	// IE will pass in empty strings as value for alpha,
+	// which will hit this case
+	if ( isNaN( value ) ) {
+		return prop.def;
+	}
+
+	if ( type.mod ) {
+		// we add mod before modding to make sure that negatives values
+		// get converted properly: -10 -> 350
+		return (value + type.mod) % type.mod;
+	}
+
+	// for now all property types without mod have min and max
+	return 0 > value ? 0 : type.max < value ? type.max : value;
+}
+
+function stringParse( string ) {
+	var inst = color(),
+		rgba = inst._rgba = [];
+
+	string = string.toLowerCase();
+
+	each( stringParsers, function( i, parser ) {
+		var parsed,
+			match = parser.re.exec( string ),
+			values = match && parser.parse( match ),
+			spaceName = parser.space || "rgba";
+
+		if ( values ) {
+			parsed = inst[ spaceName ]( values );
+
+			// if this was an rgba parse the assignment might happen twice
+			// oh well....
+			inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
+			rgba = inst._rgba = parsed._rgba;
+
+			// exit each( stringParsers ) here because we matched
+			return false;
+		}
+	});
+
+	// Found a stringParser that handled it
+	if ( rgba.length ) {
+
+		// if this came from a parsed string, force "transparent" when alpha is 0
+		// chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
+		if ( rgba.join() === "0,0,0,0" ) {
+			jQuery.extend( rgba, colors.transparent );
+		}
+		return inst;
+	}
+
+	// named colors
+	return colors[ string ];
+}
+
+color.fn = jQuery.extend( color.prototype, {
+	parse: function( red, green, blue, alpha ) {
+		if ( red === undefined ) {
+			this._rgba = [ null, null, null, null ];
+			return this;
+		}
+		if ( red.jquery || red.nodeType ) {
+			red = jQuery( red ).css( green );
+			green = undefined;
+		}
+
+		var inst = this,
+			type = jQuery.type( red ),
+			rgba = this._rgba = [];
+
+		// more than 1 argument specified - assume ( red, green, blue, alpha )
+		if ( green !== undefined ) {
+			red = [ red, green, blue, alpha ];
+			type = "array";
+		}
+
+		if ( type === "string" ) {
+			return this.parse( stringParse( red ) || colors._default );
+		}
+
+		if ( type === "array" ) {
+			each( spaces.rgba.props, function( key, prop ) {
+				rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
+			});
+			return this;
+		}
+
+		if ( type === "object" ) {
+			if ( red instanceof color ) {
+				each( spaces, function( spaceName, space ) {
+					if ( red[ space.cache ] ) {
+						inst[ space.cache ] = red[ space.cache ].slice();
+					}
+				});
+			} else {
+				each( spaces, function( spaceName, space ) {
+					var cache = space.cache;
+					each( space.props, function( key, prop ) {
+
+						// if the cache doesn't exist, and we know how to convert
+						if ( !inst[ cache ] && space.to ) {
+
+							// if the value was null, we don't need to copy it
+							// if the key was alpha, we don't need to copy it either
+							if ( key === "alpha" || red[ key ] == null ) {
+								return;
+							}
+							inst[ cache ] = space.to( inst._rgba );
+						}
+
+						// this is the only case where we allow nulls for ALL properties.
+						// call clamp with alwaysAllowEmpty
+						inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
+					});
+
+					// everything defined but alpha?
+					if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
+						// use the default of 1
+						inst[ cache ][ 3 ] = 1;
+						if ( space.from ) {
+							inst._rgba = space.from( inst[ cache ] );
+						}
+					}
+				});
+			}
+			return this;
+		}
+	},
+	is: function( compare ) {
+		var is = color( compare ),
+			same = true,
+			inst = this;
+
+		each( spaces, function( _, space ) {
+			var localCache,
+				isCache = is[ space.cache ];
+			if (isCache) {
+				localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
+				each( space.props, function( _, prop ) {
+					if ( isCache[ prop.idx ] != null ) {
+						same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
+						return same;
+					}
+				});
+			}
+			return same;
+		});
+		return same;
+	},
+	_space: function() {
+		var used = [],
+			inst = this;
+		each( spaces, function( spaceName, space ) {
+			if ( inst[ space.cache ] ) {
+				used.push( spaceName );
+			}
+		});
+		return used.pop();
+	},
+	transition: function( other, distance ) {
+		var end = color( other ),
+			spaceName = end._space(),
+			space = spaces[ spaceName ],
+			startColor = this.alpha() === 0 ? color( "transparent" ) : this,
+			start = startColor[ space.cache ] || space.to( startColor._rgba ),
+			result = start.slice();
+
+		end = end[ space.cache ];
+		each( space.props, function( key, prop ) {
+			var index = prop.idx,
+				startValue = start[ index ],
+				endValue = end[ index ],
+				type = propTypes[ prop.type ] || {};
+
+			// if null, don't override start value
+			if ( endValue === null ) {
+				return;
+			}
+			// if null - use end
+			if ( startValue === null ) {
+				result[ index ] = endValue;
+			} else {
+				if ( type.mod ) {
+					if ( endValue - startValue > type.mod / 2 ) {
+						startValue += type.mod;
+					} else if ( startValue - endValue > type.mod / 2 ) {
+						startValue -= type.mod;
+					}
+				}
+				result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
+			}
+		});
+		return this[ spaceName ]( result );
+	},
+	blend: function( opaque ) {
+		// if we are already opaque - return ourself
+		if ( this._rgba[ 3 ] === 1 ) {
+			return this;
+		}
+
+		var rgb = this._rgba.slice(),
+			a = rgb.pop(),
+			blend = color( opaque )._rgba;
+
+		return color( jQuery.map( rgb, function( v, i ) {
+			return ( 1 - a ) * blend[ i ] + a * v;
+		}));
+	},
+	toRgbaString: function() {
+		var prefix = "rgba(",
+			rgba = jQuery.map( this._rgba, function( v, i ) {
+				return v == null ? ( i > 2 ? 1 : 0 ) : v;
+			});
+
+		if ( rgba[ 3 ] === 1 ) {
+			rgba.pop();
+			prefix = "rgb(";
+		}
+
+		return prefix + rgba.join() + ")";
+	},
+	toHslaString: function() {
+		var prefix = "hsla(",
+			hsla = jQuery.map( this.hsla(), function( v, i ) {
+				if ( v == null ) {
+					v = i > 2 ? 1 : 0;
+				}
+
+				// catch 1 and 2
+				if ( i && i < 3 ) {
+					v = Math.round( v * 100 ) + "%";
+				}
+				return v;
+			});
+
+		if ( hsla[ 3 ] === 1 ) {
+			hsla.pop();
+			prefix = "hsl(";
+		}
+		return prefix + hsla.join() + ")";
+	},
+	toHexString: function( includeAlpha ) {
+		var rgba = this._rgba.slice(),
+			alpha = rgba.pop();
+
+		if ( includeAlpha ) {
+			rgba.push( ~~( alpha * 255 ) );
+		}
+
+		return "#" + jQuery.map( rgba, function( v ) {
+
+			// default to 0 when nulls exist
+			v = ( v || 0 ).toString( 16 );
+			return v.length === 1 ? "0" + v : v;
+		}).join("");
+	},
+	toString: function() {
+		return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
+	}
+});
+color.fn.parse.prototype = color.fn;
+
+// hsla conversions adapted from:
+// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
+
+function hue2rgb( p, q, h ) {
+	h = ( h + 1 ) % 1;
+	if ( h * 6 < 1 ) {
+		return p + ( q - p ) * h * 6;
+	}
+	if ( h * 2 < 1) {
+		return q;
+	}
+	if ( h * 3 < 2 ) {
+		return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
+	}
+	return p;
+}
+
+spaces.hsla.to = function( rgba ) {
+	if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
+		return [ null, null, null, rgba[ 3 ] ];
+	}
+	var r = rgba[ 0 ] / 255,
+		g = rgba[ 1 ] / 255,
+		b = rgba[ 2 ] / 255,
+		a = rgba[ 3 ],
+		max = Math.max( r, g, b ),
+		min = Math.min( r, g, b ),
+		diff = max - min,
+		add = max + min,
+		l = add * 0.5,
+		h, s;
+
+	if ( min === max ) {
+		h = 0;
+	} else if ( r === max ) {
+		h = ( 60 * ( g - b ) / diff ) + 360;
+	} else if ( g === max ) {
+		h = ( 60 * ( b - r ) / diff ) + 120;
+	} else {
+		h = ( 60 * ( r - g ) / diff ) + 240;
+	}
+
+	// chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
+	// otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
+	if ( diff === 0 ) {
+		s = 0;
+	} else if ( l <= 0.5 ) {
+		s = diff / add;
+	} else {
+		s = diff / ( 2 - add );
+	}
+	return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
+};
+
+spaces.hsla.from = function( hsla ) {
+	if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
+		return [ null, null, null, hsla[ 3 ] ];
+	}
+	var h = hsla[ 0 ] / 360,
+		s = hsla[ 1 ],
+		l = hsla[ 2 ],
+		a = hsla[ 3 ],
+		q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
+		p = 2 * l - q;
+
+	return [
+		Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
+		Math.round( hue2rgb( p, q, h ) * 255 ),
+		Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
+		a
+	];
+};
+
+each( spaces, function( spaceName, space ) {
+	var props = space.props,
+		cache = space.cache,
+		to = space.to,
+		from = space.from;
+
+	// makes rgba() and hsla()
+	color.fn[ spaceName ] = function( value ) {
+
+		// generate a cache for this space if it doesn't exist
+		if ( to && !this[ cache ] ) {
+			this[ cache ] = to( this._rgba );
+		}
+		if ( value === undefined ) {
+			return this[ cache ].slice();
+		}
+
+		var ret,
+			type = jQuery.type( value ),
+			arr = ( type === "array" || type === "object" ) ? value : arguments,
+			local = this[ cache ].slice();
+
+		each( props, function( key, prop ) {
+			var val = arr[ type === "object" ? key : prop.idx ];
+			if ( val == null ) {
+				val = local[ prop.idx ];
+			}
+			local[ prop.idx ] = clamp( val, prop );
+		});
+
+		if ( from ) {
+			ret = color( from( local ) );
+			ret[ cache ] = local;
+			return ret;
+		} else {
+			return color( local );
+		}
+	};
+
+	// makes red() green() blue() alpha() hue() saturation() lightness()
+	each( props, function( key, prop ) {
+		// alpha is included in more than one space
+		if ( color.fn[ key ] ) {
+			return;
+		}
+		color.fn[ key ] = function( value ) {
+			var vtype = jQuery.type( value ),
+				fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
+				local = this[ fn ](),
+				cur = local[ prop.idx ],
+				match;
+
+			if ( vtype === "undefined" ) {
+				return cur;
+			}
+
+			if ( vtype === "function" ) {
+				value = value.call( this, cur );
+				vtype = jQuery.type( value );
+			}
+			if ( value == null && prop.empty ) {
+				return this;
+			}
+			if ( vtype === "string" ) {
+				match = rplusequals.exec( value );
+				if ( match ) {
+					value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
+				}
+			}
+			local[ prop.idx ] = value;
+			return this[ fn ]( local );
+		};
+	});
+});
+
+// add cssHook and .fx.step function for each named hook.
+// accept a space separated string of properties
+color.hook = function( hook ) {
+	var hooks = hook.split( " " );
+	each( hooks, function( i, hook ) {
+		jQuery.cssHooks[ hook ] = {
+			set: function( elem, value ) {
+				var parsed, curElem,
+					backgroundColor = "";
+
+				if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
+					value = color( parsed || value );
+					if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
+						curElem = hook === "backgroundColor" ? elem.parentNode : elem;
+						while (
+							(backgroundColor === "" || backgroundColor === "transparent") &&
+							curElem && curElem.style
+						) {
+							try {
+								backgroundColor = jQuery.css( curElem, "backgroundColor" );
+								curElem = curElem.parentNode;
+							} catch ( e ) {
+							}
+						}
+
+						value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
+							backgroundColor :
+							"_default" );
+					}
+
+					value = value.toRgbaString();
+				}
+				try {
+					elem.style[ hook ] = value;
+				} catch ( e ) {
+					// wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
+				}
+			}
+		};
+		jQuery.fx.step[ hook ] = function( fx ) {
+			if ( !fx.colorInit ) {
+				fx.start = color( fx.elem, hook );
+				fx.end = color( fx.end );
+				fx.colorInit = true;
+			}
+			jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
+		};
+	});
+
+};
+
+color.hook( stepHooks );
+
+jQuery.cssHooks.borderColor = {
+	expand: function( value ) {
+		var expanded = {};
+
+		each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
+			expanded[ "border" + part + "Color" ] = value;
+		});
+		return expanded;
+	}
+};
+
+// Basic color names only.
+// Usage of any of the other color names requires adding yourself or including
+// jquery.color.svg-names.js.
+colors = jQuery.Color.names = {
+	// 4.1. Basic color keywords
+	aqua: "#00ffff",
+	black: "#000000",
+	blue: "#0000ff",
+	fuchsia: "#ff00ff",
+	gray: "#808080",
+	green: "#008000",
+	lime: "#00ff00",
+	maroon: "#800000",
+	navy: "#000080",
+	olive: "#808000",
+	purple: "#800080",
+	red: "#ff0000",
+	silver: "#c0c0c0",
+	teal: "#008080",
+	white: "#ffffff",
+	yellow: "#ffff00",
+
+	// 4.2.3. "transparent" color keyword
+	transparent: [ null, null, null, 0 ],
+
+	_default: "#ffffff"
+};
+
+})( jQuery );
+
+/******************************************************************************/
+/****************************** CLASS ANIMATIONS ******************************/
+/******************************************************************************/
+(function() {
+
+var classAnimationActions = [ "add", "remove", "toggle" ],
+	shorthandStyles = {
+		border: 1,
+		borderBottom: 1,
+		borderColor: 1,
+		borderLeft: 1,
+		borderRight: 1,
+		borderTop: 1,
+		borderWidth: 1,
+		margin: 1,
+		padding: 1
+	};
+
+$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
+	$.fx.step[ prop ] = function( fx ) {
+		if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
+			jQuery.style( fx.elem, prop, fx.end );
+			fx.setAttr = true;
+		}
+	};
+});
+
+function getElementStyles( elem ) {
+	var key, len,
+		style = elem.ownerDocument.defaultView ?
+			elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
+			elem.currentStyle,
+		styles = {};
+
+	if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
+		len = style.length;
+		while ( len-- ) {
+			key = style[ len ];
+			if ( typeof style[ key ] === "string" ) {
+				styles[ $.camelCase( key ) ] = style[ key ];
+			}
+		}
+	// support: Opera, IE <9
+	} else {
+		for ( key in style ) {
+			if ( typeof style[ key ] === "string" ) {
+				styles[ key ] = style[ key ];
+			}
+		}
+	}
+
+	return styles;
+}
+
+function styleDifference( oldStyle, newStyle ) {
+	var diff = {},
+		name, value;
+
+	for ( name in newStyle ) {
+		value = newStyle[ name ];
+		if ( oldStyle[ name ] !== value ) {
+			if ( !shorthandStyles[ name ] ) {
+				if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
+					diff[ name ] = value;
+				}
+			}
+		}
+	}
+
+	return diff;
+}
+
+// support: jQuery <1.8
+if ( !$.fn.addBack ) {
+	$.fn.addBack = function( selector ) {
+		return this.add( selector == null ?
+			this.prevObject : this.prevObject.filter( selector )
+		);
+	};
+}
+
+$.effects.animateClass = function( value, duration, easing, callback ) {
+	var o = $.speed( duration, easing, callback );
+
+	return this.queue( function() {
+		var animated = $( this ),
+			baseClass = animated.attr( "class" ) || "",
+			applyClassChange,
+			allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
+
+		// map the animated objects to store the original styles.
+		allAnimations = allAnimations.map(function() {
+			var el = $( this );
+			return {
+				el: el,
+				start: getElementStyles( this )
+			};
+		});
+
+		// apply class change
+		applyClassChange = function() {
+			$.each( classAnimationActions, function(i, action) {
+				if ( value[ action ] ) {
+					animated[ action + "Class" ]( value[ action ] );
+				}
+			});
+		};
+		applyClassChange();
+
+		// map all animated objects again - calculate new styles and diff
+		allAnimations = allAnimations.map(function() {
+			this.end = getElementStyles( this.el[ 0 ] );
+			this.diff = styleDifference( this.start, this.end );
+			return this;
+		});
+
+		// apply original class
+		animated.attr( "class", baseClass );
+
+		// map all animated objects again - this time collecting a promise
+		allAnimations = allAnimations.map(function() {
+			var styleInfo = this,
+				dfd = $.Deferred(),
+				opts = $.extend({}, o, {
+					queue: false,
+					complete: function() {
+						dfd.resolve( styleInfo );
+					}
+				});
+
+			this.el.animate( this.diff, opts );
+			return dfd.promise();
+		});
+
+		// once all animations have completed:
+		$.when.apply( $, allAnimations.get() ).done(function() {
+
+			// set the final class
+			applyClassChange();
+
+			// for each animated element,
+			// clear all css properties that were animated
+			$.each( arguments, function() {
+				var el = this.el;
+				$.each( this.diff, function(key) {
+					el.css( key, "" );
+				});
+			});
+
+			// this is guarnteed to be there if you use jQuery.speed()
+			// it also handles dequeuing the next anim...
+			o.complete.call( animated[ 0 ] );
+		});
+	});
+};
+
+$.fn.extend({
+	addClass: (function( orig ) {
+		return function( classNames, speed, easing, callback ) {
+			return speed ?
+				$.effects.animateClass.call( this,
+					{ add: classNames }, speed, easing, callback ) :
+				orig.apply( this, arguments );
+		};
+	})( $.fn.addClass ),
+
+	removeClass: (function( orig ) {
+		return function( classNames, speed, easing, callback ) {
+			return arguments.length > 1 ?
+				$.effects.animateClass.call( this,
+					{ remove: classNames }, speed, easing, callback ) :
+				orig.apply( this, arguments );
+		};
+	})( $.fn.removeClass ),
+
+	toggleClass: (function( orig ) {
+		return function( classNames, force, speed, easing, callback ) {
+			if ( typeof force === "boolean" || force === undefined ) {
+				if ( !speed ) {
+					// without speed parameter
+					return orig.apply( this, arguments );
+				} else {
+					return $.effects.animateClass.call( this,
+						(force ? { add: classNames } : { remove: classNames }),
+						speed, easing, callback );
+				}
+			} else {
+				// without force parameter
+				return $.effects.animateClass.call( this,
+					{ toggle: classNames }, force, speed, easing );
+			}
+		};
+	})( $.fn.toggleClass ),
+
+	switchClass: function( remove, add, speed, easing, callback) {
+		return $.effects.animateClass.call( this, {
+			add: add,
+			remove: remove
+		}, speed, easing, callback );
+	}
+});
+
+})();
+
+/******************************************************************************/
+/*********************************** EFFECTS **********************************/
+/******************************************************************************/
+
+(function() {
+
+$.extend( $.effects, {
+	version: "1.11.4",
+
+	// Saves a set of properties in a data storage
+	save: function( element, set ) {
+		for ( var i = 0; i < set.length; i++ ) {
+			if ( set[ i ] !== null ) {
+				element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
+			}
+		}
+	},
+
+	// Restores a set of previously saved properties from a data storage
+	restore: function( element, set ) {
+		var val, i;
+		for ( i = 0; i < set.length; i++ ) {
+			if ( set[ i ] !== null ) {
+				val = element.data( dataSpace + set[ i ] );
+				// support: jQuery 1.6.2
+				// http://bugs.jquery.com/ticket/9917
+				// jQuery 1.6.2 incorrectly returns undefined for any falsy value.
+				// We can't differentiate between "" and 0 here, so we just assume
+				// empty string since it's likely to be a more common value...
+				if ( val === undefined ) {
+					val = "";
+				}
+				element.css( set[ i ], val );
+			}
+		}
+	},
+
+	setMode: function( el, mode ) {
+		if (mode === "toggle") {
+			mode = el.is( ":hidden" ) ? "show" : "hide";
+		}
+		return mode;
+	},
+
+	// Translates a [top,left] array into a baseline value
+	// this should be a little more flexible in the future to handle a string & hash
+	getBaseline: function( origin, original ) {
+		var y, x;
+		switch ( origin[ 0 ] ) {
+			case "top": y = 0; break;
+			case "middle": y = 0.5; break;
+			case "bottom": y = 1; break;
+			default: y = origin[ 0 ] / original.height;
+		}
+		switch ( origin[ 1 ] ) {
+			case "left": x = 0; break;
+			case "center": x = 0.5; break;
+			case "right": x = 1; break;
+			default: x = origin[ 1 ] / original.width;
+		}
+		return {
+			x: x,
+			y: y
+		};
+	},
+
+	// Wraps the element around a wrapper that copies position properties
+	createWrapper: function( element ) {
+
+		// if the element is already wrapped, return it
+		if ( element.parent().is( ".ui-effects-wrapper" )) {
+			return element.parent();
+		}
+
+		// wrap the element
+		var props = {
+				width: element.outerWidth(true),
+				height: element.outerHeight(true),
+				"float": element.css( "float" )
+			},
+			wrapper = $( "<div></div>" )
+				.addClass( "ui-effects-wrapper" )
+				.css({
+					fontSize: "100%",
+					background: "transparent",
+					border: "none",
+					margin: 0,
+					padding: 0
+				}),
+			// Store the size in case width/height are defined in % - Fixes #5245
+			size = {
+				width: element.width(),
+				height: element.height()
+			},
+			active = document.activeElement;
+
+		// support: Firefox
+		// Firefox incorrectly exposes anonymous content
+		// https://bugzilla.mozilla.org/show_bug.cgi?id=561664
+		try {
+			active.id;
+		} catch ( e ) {
+			active = document.body;
+		}
+
+		element.wrap( wrapper );
+
+		// Fixes #7595 - Elements lose focus when wrapped.
+		if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+			$( active ).focus();
+		}
+
+		wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
+
+		// transfer positioning properties to the wrapper
+		if ( element.css( "position" ) === "static" ) {
+			wrapper.css({ position: "relative" });
+			element.css({ position: "relative" });
+		} else {
+			$.extend( props, {
+				position: element.css( "position" ),
+				zIndex: element.css( "z-index" )
+			});
+			$.each([ "top", "left", "bottom", "right" ], function(i, pos) {
+				props[ pos ] = element.css( pos );
+				if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
+					props[ pos ] = "auto";
+				}
+			});
+			element.css({
+				position: "relative",
+				top: 0,
+				left: 0,
+				right: "auto",
+				bottom: "auto"
+			});
+		}
+		element.css(size);
+
+		return wrapper.css( props ).show();
+	},
+
+	removeWrapper: function( element ) {
+		var active = document.activeElement;
+
+		if ( element.parent().is( ".ui-effects-wrapper" ) ) {
+			element.parent().replaceWith( element );
+
+			// Fixes #7595 - Elements lose focus when wrapped.
+			if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+				$( active ).focus();
+			}
+		}
+
+		return element;
+	},
+
+	setTransition: function( element, list, factor, value ) {
+		value = value || {};
+		$.each( list, function( i, x ) {
+			var unit = element.cssUnit( x );
+			if ( unit[ 0 ] > 0 ) {
+				value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
+			}
+		});
+		return value;
+	}
+});
+
+// return an effect options object for the given parameters:
+function _normalizeArguments( effect, options, speed, callback ) {
+
+	// allow passing all options as the first parameter
+	if ( $.isPlainObject( effect ) ) {
+		options = effect;
+		effect = effect.effect;
+	}
+
+	// convert to an object
+	effect = { effect: effect };
+
+	// catch (effect, null, ...)
+	if ( options == null ) {
+		options = {};
+	}
+
+	// catch (effect, callback)
+	if ( $.isFunction( options ) ) {
+		callback = options;
+		speed = null;
+		options = {};
+	}
+
+	// catch (effect, speed, ?)
+	if ( typeof options === "number" || $.fx.speeds[ options ] ) {
+		callback = speed;
+		speed = options;
+		options = {};
+	}
+
+	// catch (effect, options, callback)
+	if ( $.isFunction( speed ) ) {
+		callback = speed;
+		speed = null;
+	}
+
+	// add options to effect
+	if ( options ) {
+		$.extend( effect, options );
+	}
+
+	speed = speed || options.duration;
+	effect.duration = $.fx.off ? 0 :
+		typeof speed === "number" ? speed :
+		speed in $.fx.speeds ? $.fx.speeds[ speed ] :
+		$.fx.speeds._default;
+
+	effect.complete = callback || options.complete;
+
+	return effect;
+}
+
+function standardAnimationOption( option ) {
+	// Valid standard speeds (nothing, number, named speed)
+	if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
+		return true;
+	}
+
+	// Invalid strings - treat as "normal" speed
+	if ( typeof option === "string" && !$.effects.effect[ option ] ) {
+		return true;
+	}
+
+	// Complete callback
+	if ( $.isFunction( option ) ) {
+		return true;
+	}
+
+	// Options hash (but not naming an effect)
+	if ( typeof option === "object" && !option.effect ) {
+		return true;
+	}
+
+	// Didn't match any standard API
+	return false;
+}
+
+$.fn.extend({
+	effect: function( /* effect, options, speed, callback */ ) {
+		var args = _normalizeArguments.apply( this, arguments ),
+			mode = args.mode,
+			queue = args.queue,
+			effectMethod = $.effects.effect[ args.effect ];
+
+		if ( $.fx.off || !effectMethod ) {
+			// delegate to the original method (e.g., .show()) if possible
+			if ( mode ) {
+				return this[ mode ]( args.duration, args.complete );
+			} else {
+				return this.each( function() {
+					if ( args.complete ) {
+						args.complete.call( this );
+					}
+				});
+			}
+		}
+
+		function run( next ) {
+			var elem = $( this ),
+				complete = args.complete,
+				mode = args.mode;
+
+			function done() {
+				if ( $.isFunction( complete ) ) {
+					complete.call( elem[0] );
+				}
+				if ( $.isFunction( next ) ) {
+					next();
+				}
+			}
+
+			// If the element already has the correct final state, delegate to
+			// the core methods so the internal tracking of "olddisplay" works.
+			if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
+				elem[ mode ]();
+				done();
+			} else {
+				effectMethod.call( elem[0], args, done );
+			}
+		}
+
+		return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
+	},
+
+	show: (function( orig ) {
+		return function( option ) {
+			if ( standardAnimationOption( option ) ) {
+				return orig.apply( this, arguments );
+			} else {
+				var args = _normalizeArguments.apply( this, arguments );
+				args.mode = "show";
+				return this.effect.call( this, args );
+			}
+		};
+	})( $.fn.show ),
+
+	hide: (function( orig ) {
+		return function( option ) {
+			if ( standardAnimationOption( option ) ) {
+				return orig.apply( this, arguments );
+			} else {
+				var args = _normalizeArguments.apply( this, arguments );
+				args.mode = "hide";
+				return this.effect.call( this, args );
+			}
+		};
+	})( $.fn.hide ),
+
+	toggle: (function( orig ) {
+		return function( option ) {
+			if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
+				return orig.apply( this, arguments );
+			} else {
+				var args = _normalizeArguments.apply( this, arguments );
+				args.mode = "toggle";
+				return this.effect.call( this, args );
+			}
+		};
+	})( $.fn.toggle ),
+
+	// helper functions
+	cssUnit: function(key) {
+		var style = this.css( key ),
+			val = [];
+
+		$.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
+			if ( style.indexOf( unit ) > 0 ) {
+				val = [ parseFloat( style ), unit ];
+			}
+		});
+		return val;
+	}
+});
+
+})();
+
+/******************************************************************************/
+/*********************************** EASING ***********************************/
+/******************************************************************************/
+
+(function() {
+
+// based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
+
+var baseEasings = {};
+
+$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
+	baseEasings[ name ] = function( p ) {
+		return Math.pow( p, i + 2 );
+	};
+});
+
+$.extend( baseEasings, {
+	Sine: function( p ) {
+		return 1 - Math.cos( p * Math.PI / 2 );
+	},
+	Circ: function( p ) {
+		return 1 - Math.sqrt( 1 - p * p );
+	},
+	Elastic: function( p ) {
+		return p === 0 || p === 1 ? p :
+			-Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
+	},
+	Back: function( p ) {
+		return p * p * ( 3 * p - 2 );
+	},
+	Bounce: function( p ) {
+		var pow2,
+			bounce = 4;
+
+		while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
+		return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
+	}
+});
+
+$.each( baseEasings, function( name, easeIn ) {
+	$.easing[ "easeIn" + name ] = easeIn;
+	$.easing[ "easeOut" + name ] = function( p ) {
+		return 1 - easeIn( 1 - p );
+	};
+	$.easing[ "easeInOut" + name ] = function( p ) {
+		return p < 0.5 ?
+			easeIn( p * 2 ) / 2 :
+			1 - easeIn( p * -2 + 2 ) / 2;
+	};
+});
+
+})();
+
+var effect = $.effects;
+
+
+/*!
+ * jQuery UI Effects Blind 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/blind-effect/
+ */
+
+
+var effectBlind = $.effects.effect.blind = function( o, done ) {
+	// Create element
+	var el = $( this ),
+		rvertical = /up|down|vertical/,
+		rpositivemotion = /up|left|vertical|horizontal/,
+		props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+		mode = $.effects.setMode( el, o.mode || "hide" ),
+		direction = o.direction || "up",
+		vertical = rvertical.test( direction ),
+		ref = vertical ? "height" : "width",
+		ref2 = vertical ? "top" : "left",
+		motion = rpositivemotion.test( direction ),
+		animation = {},
+		show = mode === "show",
+		wrapper, distance, margin;
+
+	// if already wrapped, the wrapper's properties are my property. #6245
+	if ( el.parent().is( ".ui-effects-wrapper" ) ) {
+		$.effects.save( el.parent(), props );
+	} else {
+		$.effects.save( el, props );
+	}
+	el.show();
+	wrapper = $.effects.createWrapper( el ).css({
+		overflow: "hidden"
+	});
+
+	distance = wrapper[ ref ]();
+	margin = parseFloat( wrapper.css( ref2 ) ) || 0;
+
+	animation[ ref ] = show ? distance : 0;
+	if ( !motion ) {
+		el
+			.css( vertical ? "bottom" : "right", 0 )
+			.css( vertical ? "top" : "left", "auto" )
+			.css({ position: "absolute" });
+
+		animation[ ref2 ] = show ? margin : distance + margin;
+	}
+
+	// start at 0 if we are showing
+	if ( show ) {
+		wrapper.css( ref, 0 );
+		if ( !motion ) {
+			wrapper.css( ref2, margin + distance );
+		}
+	}
+
+	// Animate
+	wrapper.animate( animation, {
+		duration: o.duration,
+		easing: o.easing,
+		queue: false,
+		complete: function() {
+			if ( mode === "hide" ) {
+				el.hide();
+			}
+			$.effects.restore( el, props );
+			$.effects.removeWrapper( el );
+			done();
+		}
+	});
+};
+
+
+/*!
+ * jQuery UI Effects Bounce 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/bounce-effect/
+ */
+
+
+var effectBounce = $.effects.effect.bounce = function( o, done ) {
+	var el = $( this ),
+		props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+
+		// defaults:
+		mode = $.effects.setMode( el, o.mode || "effect" ),
+		hide = mode === "hide",
+		show = mode === "show",
+		direction = o.direction || "up",
+		distance = o.distance,
+		times = o.times || 5,
+
+		// number of internal animations
+		anims = times * 2 + ( show || hide ? 1 : 0 ),
+		speed = o.duration / anims,
+		easing = o.easing,
+
+		// utility:
+		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+		motion = ( direction === "up" || direction === "left" ),
+		i,
+		upAnim,
+		downAnim,
+
+		// we will need to re-assemble the queue to stack our animations in place
+		queue = el.queue(),
+		queuelen = queue.length;
+
+	// Avoid touching opacity to prevent clearType and PNG issues in IE
+	if ( show || hide ) {
+		props.push( "opacity" );
+	}
+
+	$.effects.save( el, props );
+	el.show();
+	$.effects.createWrapper( el ); // Create Wrapper
+
+	// default distance for the BIGGEST bounce is the outer Distance / 3
+	if ( !distance ) {
+		distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
+	}
+
+	if ( show ) {
+		downAnim = { opacity: 1 };
+		downAnim[ ref ] = 0;
+
+		// if we are showing, force opacity 0 and set the initial position
+		// then do the "first" animation
+		el.css( "opacity", 0 )
+			.css( ref, motion ? -distance * 2 : distance * 2 )
+			.animate( downAnim, speed, easing );
+	}
+
+	// start at the smallest distance if we are hiding
+	if ( hide ) {
+		distance = distance / Math.pow( 2, times - 1 );
+	}
+
+	downAnim = {};
+	downAnim[ ref ] = 0;
+	// Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
+	for ( i = 0; i < times; i++ ) {
+		upAnim = {};
+		upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
+
+		el.animate( upAnim, speed, easing )
+			.animate( downAnim, speed, easing );
+
+		distance = hide ? distance * 2 : distance / 2;
+	}
+
+	// Last Bounce when Hiding
+	if ( hide ) {
+		upAnim = { opacity: 0 };
+		upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
+
+		el.animate( upAnim, speed, easing );
+	}
+
+	el.queue(function() {
+		if ( hide ) {
+			el.hide();
+		}
+		$.effects.restore( el, props );
+		$.effects.removeWrapper( el );
+		done();
+	});
+
+	// inject all the animations we just queued to be first in line (after "inprogress")
+	if ( queuelen > 1) {
+		queue.splice.apply( queue,
+			[ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+	}
+	el.dequeue();
+
+};
+
+
+/*!
+ * jQuery UI Effects Clip 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/clip-effect/
+ */
+
+
+var effectClip = $.effects.effect.clip = function( o, done ) {
+	// Create element
+	var el = $( this ),
+		props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+		mode = $.effects.setMode( el, o.mode || "hide" ),
+		show = mode === "show",
+		direction = o.direction || "vertical",
+		vert = direction === "vertical",
+		size = vert ? "height" : "width",
+		position = vert ? "top" : "left",
+		animation = {},
+		wrapper, animate, distance;
+
+	// Save & Show
+	$.effects.save( el, props );
+	el.show();
+
+	// Create Wrapper
+	wrapper = $.effects.createWrapper( el ).css({
+		overflow: "hidden"
+	});
+	animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
+	distance = animate[ size ]();
+
+	// Shift
+	if ( show ) {
+		animate.css( size, 0 );
+		animate.css( position, distance / 2 );
+	}
+
+	// Create Animation Object:
+	animation[ size ] = show ? distance : 0;
+	animation[ position ] = show ? 0 : distance / 2;
+
+	// Animate
+	animate.animate( animation, {
+		queue: false,
+		duration: o.duration,
+		easing: o.easing,
+		complete: function() {
+			if ( !show ) {
+				el.hide();
+			}
+			$.effects.restore( el, props );
+			$.effects.removeWrapper( el );
+			done();
+		}
+	});
+
+};
+
+
+/*!
+ * jQuery UI Effects Drop 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/drop-effect/
+ */
+
+
+var effectDrop = $.effects.effect.drop = function( o, done ) {
+
+	var el = $( this ),
+		props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
+		mode = $.effects.setMode( el, o.mode || "hide" ),
+		show = mode === "show",
+		direction = o.direction || "left",
+		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+		motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
+		animation = {
+			opacity: show ? 1 : 0
+		},
+		distance;
+
+	// Adjust
+	$.effects.save( el, props );
+	el.show();
+	$.effects.createWrapper( el );
+
+	distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
+
+	if ( show ) {
+		el
+			.css( "opacity", 0 )
+			.css( ref, motion === "pos" ? -distance : distance );
+	}
+
+	// Animation
+	animation[ ref ] = ( show ?
+		( motion === "pos" ? "+=" : "-=" ) :
+		( motion === "pos" ? "-=" : "+=" ) ) +
+		distance;
+
+	// Animate
+	el.animate( animation, {
+		queue: false,
+		duration: o.duration,
+		easing: o.easing,
+		complete: function() {
+			if ( mode === "hide" ) {
+				el.hide();
+			}
+			$.effects.restore( el, props );
+			$.effects.removeWrapper( el );
+			done();
+		}
+	});
+};
+
+
+/*!
+ * jQuery UI Effects Explode 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/explode-effect/
+ */
+
+
+var effectExplode = $.effects.effect.explode = function( o, done ) {
+
+	var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
+		cells = rows,
+		el = $( this ),
+		mode = $.effects.setMode( el, o.mode || "hide" ),
+		show = mode === "show",
+
+		// show and then visibility:hidden the element before calculating offset
+		offset = el.show().css( "visibility", "hidden" ).offset(),
+
+		// width and height of a piece
+		width = Math.ceil( el.outerWidth() / cells ),
+		height = Math.ceil( el.outerHeight() / rows ),
+		pieces = [],
+
+		// loop
+		i, j, left, top, mx, my;
+
+	// children animate complete:
+	function childComplete() {
+		pieces.push( this );
+		if ( pieces.length === rows * cells ) {
+			animComplete();
+		}
+	}
+
+	// clone the element for each row and cell.
+	for ( i = 0; i < rows ; i++ ) { // ===>
+		top = offset.top + i * height;
+		my = i - ( rows - 1 ) / 2 ;
+
+		for ( j = 0; j < cells ; j++ ) { // |||
+			left = offset.left + j * width;
+			mx = j - ( cells - 1 ) / 2 ;
+
+			// Create a clone of the now hidden main element that will be absolute positioned
+			// within a wrapper div off the -left and -top equal to size of our pieces
+			el
+				.clone()
+				.appendTo( "body" )
+				.wrap( "<div></div>" )
+				.css({
+					position: "absolute",
+					visibility: "visible",
+					left: -j * width,
+					top: -i * height
+				})
+
+			// select the wrapper - make it overflow: hidden and absolute positioned based on
+			// where the original was located +left and +top equal to the size of pieces
+				.parent()
+				.addClass( "ui-effects-explode" )
+				.css({
+					position: "absolute",
+					overflow: "hidden",
+					width: width,
+					height: height,
+					left: left + ( show ? mx * width : 0 ),
+					top: top + ( show ? my * height : 0 ),
+					opacity: show ? 0 : 1
+				}).animate({
+					left: left + ( show ? 0 : mx * width ),
+					top: top + ( show ? 0 : my * height ),
+					opacity: show ? 1 : 0
+				}, o.duration || 500, o.easing, childComplete );
+		}
+	}
+
+	function animComplete() {
+		el.css({
+			visibility: "visible"
+		});
+		$( pieces ).remove();
+		if ( !show ) {
+			el.hide();
+		}
+		done();
+	}
+};
+
+
+/*!
+ * jQuery UI Effects Fade 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/fade-effect/
+ */
+
+
+var effectFade = $.effects.effect.fade = function( o, done ) {
+	var el = $( this ),
+		mode = $.effects.setMode( el, o.mode || "toggle" );
+
+	el.animate({
+		opacity: mode
+	}, {
+		queue: false,
+		duration: o.duration,
+		easing: o.easing,
+		complete: done
+	});
+};
+
+
+/*!
+ * jQuery UI Effects Fold 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/fold-effect/
+ */
+
+
+var effectFold = $.effects.effect.fold = function( o, done ) {
+
+	// Create element
+	var el = $( this ),
+		props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+		mode = $.effects.setMode( el, o.mode || "hide" ),
+		show = mode === "show",
+		hide = mode === "hide",
+		size = o.size || 15,
+		percent = /([0-9]+)%/.exec( size ),
+		horizFirst = !!o.horizFirst,
+		widthFirst = show !== horizFirst,
+		ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
+		duration = o.duration / 2,
+		wrapper, distance,
+		animation1 = {},
+		animation2 = {};
+
+	$.effects.save( el, props );
+	el.show();
+
+	// Create Wrapper
+	wrapper = $.effects.createWrapper( el ).css({
+		overflow: "hidden"
+	});
+	distance = widthFirst ?
+		[ wrapper.width(), wrapper.height() ] :
+		[ wrapper.height(), wrapper.width() ];
+
+	if ( percent ) {
+		size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
+	}
+	if ( show ) {
+		wrapper.css( horizFirst ? {
+			height: 0,
+			width: size
+		} : {
+			height: size,
+			width: 0
+		});
+	}
+
+	// Animation
+	animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
+	animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
+
+	// Animate
+	wrapper
+		.animate( animation1, duration, o.easing )
+		.animate( animation2, duration, o.easing, function() {
+			if ( hide ) {
+				el.hide();
+			}
+			$.effects.restore( el, props );
+			$.effects.removeWrapper( el );
+			done();
+		});
+
+};
+
+
+/*!
+ * jQuery UI Effects Highlight 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/highlight-effect/
+ */
+
+
+var effectHighlight = $.effects.effect.highlight = function( o, done ) {
+	var elem = $( this ),
+		props = [ "backgroundImage", "backgroundColor", "opacity" ],
+		mode = $.effects.setMode( elem, o.mode || "show" ),
+		animation = {
+			backgroundColor: elem.css( "backgroundColor" )
+		};
+
+	if (mode === "hide") {
+		animation.opacity = 0;
+	}
+
+	$.effects.save( elem, props );
+
+	elem
+		.show()
+		.css({
+			backgroundImage: "none",
+			backgroundColor: o.color || "#ffff99"
+		})
+		.animate( animation, {
+			queue: false,
+			duration: o.duration,
+			easing: o.easing,
+			complete: function() {
+				if ( mode === "hide" ) {
+					elem.hide();
+				}
+				$.effects.restore( elem, props );
+				done();
+			}
+		});
+};
+
+
+/*!
+ * jQuery UI Effects Size 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/size-effect/
+ */
+
+
+var effectSize = $.effects.effect.size = function( o, done ) {
+
+	// Create element
+	var original, baseline, factor,
+		el = $( this ),
+		props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
+
+		// Always restore
+		props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
+
+		// Copy for children
+		props2 = [ "width", "height", "overflow" ],
+		cProps = [ "fontSize" ],
+		vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
+		hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
+
+		// Set options
+		mode = $.effects.setMode( el, o.mode || "effect" ),
+		restore = o.restore || mode !== "effect",
+		scale = o.scale || "both",
+		origin = o.origin || [ "middle", "center" ],
+		position = el.css( "position" ),
+		props = restore ? props0 : props1,
+		zero = {
+			height: 0,
+			width: 0,
+			outerHeight: 0,
+			outerWidth: 0
+		};
+
+	if ( mode === "show" ) {
+		el.show();
+	}
+	original = {
+		height: el.height(),
+		width: el.width(),
+		outerHeight: el.outerHeight(),
+		outerWidth: el.outerWidth()
+	};
+
+	if ( o.mode === "toggle" && mode === "show" ) {
+		el.from = o.to || zero;
+		el.to = o.from || original;
+	} else {
+		el.from = o.from || ( mode === "show" ? zero : original );
+		el.to = o.to || ( mode === "hide" ? zero : original );
+	}
+
+	// Set scaling factor
+	factor = {
+		from: {
+			y: el.from.height / original.height,
+			x: el.from.width / original.width
+		},
+		to: {
+			y: el.to.height / original.height,
+			x: el.to.width / original.width
+		}
+	};
+
+	// Scale the css box
+	if ( scale === "box" || scale === "both" ) {
+
+		// Vertical props scaling
+		if ( factor.from.y !== factor.to.y ) {
+			props = props.concat( vProps );
+			el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
+			el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
+		}
+
+		// Horizontal props scaling
+		if ( factor.from.x !== factor.to.x ) {
+			props = props.concat( hProps );
+			el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
+			el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
+		}
+	}
+
+	// Scale the content
+	if ( scale === "content" || scale === "both" ) {
+
+		// Vertical props scaling
+		if ( factor.from.y !== factor.to.y ) {
+			props = props.concat( cProps ).concat( props2 );
+			el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
+			el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
+		}
+	}
+
+	$.effects.save( el, props );
+	el.show();
+	$.effects.createWrapper( el );
+	el.css( "overflow", "hidden" ).css( el.from );
+
+	// Adjust
+	if (origin) { // Calculate baseline shifts
+		baseline = $.effects.getBaseline( origin, original );
+		el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
+		el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
+		el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
+		el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
+	}
+	el.css( el.from ); // set top & left
+
+	// Animate
+	if ( scale === "content" || scale === "both" ) { // Scale the children
+
+		// Add margins/font-size
+		vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
+		hProps = hProps.concat([ "marginLeft", "marginRight" ]);
+		props2 = props0.concat(vProps).concat(hProps);
+
+		el.find( "*[width]" ).each( function() {
+			var child = $( this ),
+				c_original = {
+					height: child.height(),
+					width: child.width(),
+					outerHeight: child.outerHeight(),
+					outerWidth: child.outerWidth()
+				};
+			if (restore) {
+				$.effects.save(child, props2);
+			}
+
+			child.from = {
+				height: c_original.height * factor.from.y,
+				width: c_original.width * factor.from.x,
+				outerHeight: c_original.outerHeight * factor.from.y,
+				outerWidth: c_original.outerWidth * factor.from.x
+			};
+			child.to = {
+				height: c_original.height * factor.to.y,
+				width: c_original.width * factor.to.x,
+				outerHeight: c_original.height * factor.to.y,
+				outerWidth: c_original.width * factor.to.x
+			};
+
+			// Vertical props scaling
+			if ( factor.from.y !== factor.to.y ) {
+				child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
+				child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
+			}
+
+			// Horizontal props scaling
+			if ( factor.from.x !== factor.to.x ) {
+				child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
+				child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
+			}
+
+			// Animate children
+			child.css( child.from );
+			child.animate( child.to, o.duration, o.easing, function() {
+
+				// Restore children
+				if ( restore ) {
+					$.effects.restore( child, props2 );
+				}
+			});
+		});
+	}
+
+	// Animate
+	el.animate( el.to, {
+		queue: false,
+		duration: o.duration,
+		easing: o.easing,
+		complete: function() {
+			if ( el.to.opacity === 0 ) {
+				el.css( "opacity", el.from.opacity );
+			}
+			if ( mode === "hide" ) {
+				el.hide();
+			}
+			$.effects.restore( el, props );
+			if ( !restore ) {
+
+				// we need to calculate our new positioning based on the scaling
+				if ( position === "static" ) {
+					el.css({
+						position: "relative",
+						top: el.to.top,
+						left: el.to.left
+					});
+				} else {
+					$.each([ "top", "left" ], function( idx, pos ) {
+						el.css( pos, function( _, str ) {
+							var val = parseInt( str, 10 ),
+								toRef = idx ? el.to.left : el.to.top;
+
+							// if original was "auto", recalculate the new value from wrapper
+							if ( str === "auto" ) {
+								return toRef + "px";
+							}
+
+							return val + toRef + "px";
+						});
+					});
+				}
+			}
+
+			$.effects.removeWrapper( el );
+			done();
+		}
+	});
+
+};
+
+
+/*!
+ * jQuery UI Effects Scale 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/scale-effect/
+ */
+
+
+var effectScale = $.effects.effect.scale = function( o, done ) {
+
+	// Create element
+	var el = $( this ),
+		options = $.extend( true, {}, o ),
+		mode = $.effects.setMode( el, o.mode || "effect" ),
+		percent = parseInt( o.percent, 10 ) ||
+			( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
+		direction = o.direction || "both",
+		origin = o.origin,
+		original = {
+			height: el.height(),
+			width: el.width(),
+			outerHeight: el.outerHeight(),
+			outerWidth: el.outerWidth()
+		},
+		factor = {
+			y: direction !== "horizontal" ? (percent / 100) : 1,
+			x: direction !== "vertical" ? (percent / 100) : 1
+		};
+
+	// We are going to pass this effect to the size effect:
+	options.effect = "size";
+	options.queue = false;
+	options.complete = done;
+
+	// Set default origin and restore for show/hide
+	if ( mode !== "effect" ) {
+		options.origin = origin || [ "middle", "center" ];
+		options.restore = true;
+	}
+
+	options.from = o.from || ( mode === "show" ? {
+		height: 0,
+		width: 0,
+		outerHeight: 0,
+		outerWidth: 0
+	} : original );
+	options.to = {
+		height: original.height * factor.y,
+		width: original.width * factor.x,
+		outerHeight: original.outerHeight * factor.y,
+		outerWidth: original.outerWidth * factor.x
+	};
+
+	// Fade option to support puff
+	if ( options.fade ) {
+		if ( mode === "show" ) {
+			options.from.opacity = 0;
+			options.to.opacity = 1;
+		}
+		if ( mode === "hide" ) {
+			options.from.opacity = 1;
+			options.to.opacity = 0;
+		}
+	}
+
+	// Animate
+	el.effect( options );
+
+};
+
+
+/*!
+ * jQuery UI Effects Puff 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/puff-effect/
+ */
+
+
+var effectPuff = $.effects.effect.puff = function( o, done ) {
+	var elem = $( this ),
+		mode = $.effects.setMode( elem, o.mode || "hide" ),
+		hide = mode === "hide",
+		percent = parseInt( o.percent, 10 ) || 150,
+		factor = percent / 100,
+		original = {
+			height: elem.height(),
+			width: elem.width(),
+			outerHeight: elem.outerHeight(),
+			outerWidth: elem.outerWidth()
+		};
+
+	$.extend( o, {
+		effect: "scale",
+		queue: false,
+		fade: true,
+		mode: mode,
+		complete: done,
+		percent: hide ? percent : 100,
+		from: hide ?
+			original :
+			{
+				height: original.height * factor,
+				width: original.width * factor,
+				outerHeight: original.outerHeight * factor,
+				outerWidth: original.outerWidth * factor
+			}
+	});
+
+	elem.effect( o );
+};
+
+
+/*!
+ * jQuery UI Effects Pulsate 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/pulsate-effect/
+ */
+
+
+var effectPulsate = $.effects.effect.pulsate = function( o, done ) {
+	var elem = $( this ),
+		mode = $.effects.setMode( elem, o.mode || "show" ),
+		show = mode === "show",
+		hide = mode === "hide",
+		showhide = ( show || mode === "hide" ),
+
+		// showing or hiding leaves of the "last" animation
+		anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
+		duration = o.duration / anims,
+		animateTo = 0,
+		queue = elem.queue(),
+		queuelen = queue.length,
+		i;
+
+	if ( show || !elem.is(":visible")) {
+		elem.css( "opacity", 0 ).show();
+		animateTo = 1;
+	}
+
+	// anims - 1 opacity "toggles"
+	for ( i = 1; i < anims; i++ ) {
+		elem.animate({
+			opacity: animateTo
+		}, duration, o.easing );
+		animateTo = 1 - animateTo;
+	}
+
+	elem.animate({
+		opacity: animateTo
+	}, duration, o.easing);
+
+	elem.queue(function() {
+		if ( hide ) {
+			elem.hide();
+		}
+		done();
+	});
+
+	// We just queued up "anims" animations, we need to put them next in the queue
+	if ( queuelen > 1 ) {
+		queue.splice.apply( queue,
+			[ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+	}
+	elem.dequeue();
+};
+
+
+/*!
+ * jQuery UI Effects Shake 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/shake-effect/
+ */
+
+
+var effectShake = $.effects.effect.shake = function( o, done ) {
+
+	var el = $( this ),
+		props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+		mode = $.effects.setMode( el, o.mode || "effect" ),
+		direction = o.direction || "left",
+		distance = o.distance || 20,
+		times = o.times || 3,
+		anims = times * 2 + 1,
+		speed = Math.round( o.duration / anims ),
+		ref = (direction === "up" || direction === "down") ? "top" : "left",
+		positiveMotion = (direction === "up" || direction === "left"),
+		animation = {},
+		animation1 = {},
+		animation2 = {},
+		i,
+
+		// we will need to re-assemble the queue to stack our animations in place
+		queue = el.queue(),
+		queuelen = queue.length;
+
+	$.effects.save( el, props );
+	el.show();
+	$.effects.createWrapper( el );
+
+	// Animation
+	animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
+	animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
+	animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
+
+	// Animate
+	el.animate( animation, speed, o.easing );
+
+	// Shakes
+	for ( i = 1; i < times; i++ ) {
+		el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
+	}
+	el
+		.animate( animation1, speed, o.easing )
+		.animate( animation, speed / 2, o.easing )
+		.queue(function() {
+			if ( mode === "hide" ) {
+				el.hide();
+			}
+			$.effects.restore( el, props );
+			$.effects.removeWrapper( el );
+			done();
+		});
+
+	// inject all the animations we just queued to be first in line (after "inprogress")
+	if ( queuelen > 1) {
+		queue.splice.apply( queue,
+			[ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+	}
+	el.dequeue();
+
+};
+
+
+/*!
+ * jQuery UI Effects Slide 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/slide-effect/
+ */
+
+
+var effectSlide = $.effects.effect.slide = function( o, done ) {
+
+	// Create element
+	var el = $( this ),
+		props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
+		mode = $.effects.setMode( el, o.mode || "show" ),
+		show = mode === "show",
+		direction = o.direction || "left",
+		ref = (direction === "up" || direction === "down") ? "top" : "left",
+		positiveMotion = (direction === "up" || direction === "left"),
+		distance,
+		animation = {};
+
+	// Adjust
+	$.effects.save( el, props );
+	el.show();
+	distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
+
+	$.effects.createWrapper( el ).css({
+		overflow: "hidden"
+	});
+
+	if ( show ) {
+		el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
+	}
+
+	// Animation
+	animation[ ref ] = ( show ?
+		( positiveMotion ? "+=" : "-=") :
+		( positiveMotion ? "-=" : "+=")) +
+		distance;
+
+	// Animate
+	el.animate( animation, {
+		queue: false,
+		duration: o.duration,
+		easing: o.easing,
+		complete: function() {
+			if ( mode === "hide" ) {
+				el.hide();
+			}
+			$.effects.restore( el, props );
+			$.effects.removeWrapper( el );
+			done();
+		}
+	});
+};
+
+
+/*!
+ * jQuery UI Effects Transfer 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/transfer-effect/
+ */
+
+
+var effectTransfer = $.effects.effect.transfer = function( o, done ) {
+	var elem = $( this ),
+		target = $( o.to ),
+		targetFixed = target.css( "position" ) === "fixed",
+		body = $("body"),
+		fixTop = targetFixed ? body.scrollTop() : 0,
+		fixLeft = targetFixed ? body.scrollLeft() : 0,
+		endPosition = target.offset(),
+		animation = {
+			top: endPosition.top - fixTop,
+			left: endPosition.left - fixLeft,
+			height: target.innerHeight(),
+			width: target.innerWidth()
+		},
+		startPosition = elem.offset(),
+		transfer = $( "<div class='ui-effects-transfer'></div>" )
+			.appendTo( document.body )
+			.addClass( o.className )
+			.css({
+				top: startPosition.top - fixTop,
+				left: startPosition.left - fixLeft,
+				height: elem.innerHeight(),
+				width: elem.innerWidth(),
+				position: targetFixed ? "fixed" : "absolute"
+			})
+			.animate( animation, o.duration, o.easing, function() {
+				transfer.remove();
+				done();
+			});
+};
+
+
+
+}));
\ No newline at end of file
diff --git a/htdocs/Libs/JQueryUI/jquery-ui.min.css b/htdocs/Libs/JQueryUI/jquery-ui.min.css
new file mode 100644
index 0000000..b58421b
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/jquery-ui.min.css
@@ -0,0 +1,7 @@
+/*! jQuery UI - v1.11.4 - 2016-04-11
+* http://jqueryui.com
+* Includes: core.css, draggable.css, resizable.css, selectable.css, sortable.css, accordion.css, autocomplete.css, button.css, datepicker.css, dialog.css, menu.css, progressbar.css, selectmenu.css, slider.css, spinner.css, tabs.css, tooltip.css, theme.css
+* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;min-height:0;font-size:100%}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:none}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;cursor:pointer;min-height:0;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-button{display:inline-block;overflow:hidden;position:relative;text-decoration:none;cursor:pointer}.ui-selectmenu-button span.ui-icon{right:0.5em;left:auto;margin-top:-8px;position:absolute;top:50%}.ui-selectmenu-button span.ui-selectmenu-text{text-align:left;padding:0.4em 2.1em 0.4em 1em;display:block;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_888888_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_454545_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_454545_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_2e83ff_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cd0a0a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#aaa;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px}
\ No newline at end of file
diff --git a/htdocs/Libs/JQueryUI/jquery-ui.min.js b/htdocs/Libs/JQueryUI/jquery-ui.min.js
new file mode 100644
index 0000000..07d2dc9
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/jquery-ui.min.js
@@ -0,0 +1,13 @@
+/*! jQuery UI - v1.11.4 - 2016-04-10
+* http://jqueryui.com
+* Includes: core.js, widget.js, mouse.js, position.js, draggable.js, droppable.js, resizable.js, selectable.js, sortable.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, menu.js, progressbar.js, selectmenu.js, slider.js, spinner.js, tabs.js, tooltip.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+(function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e(jQuery)})(function(e){function t(t,s){var n,a,o,r=t.nodeName.toLowerCase();return"area"===r?(n=t.parentNode,a=n.name,t.href&&a&&"map"===n.nodeName.toLowerCase()?(o=e("img[usemap='#"+a+"']")[0],!!o&&i(o)):!1):(/^(input|select|textarea|button|object)$/.test(r)?!t.disabled:"a"===r?t.href||s:s)&&i(t)}function i(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}function s(e){for(var t,i;e.length&&e[0]!==document;){if(t=e.css("position"),("absolute"===t||"relative"===t||"fixed"===t)&&(i=parseInt(e.css("zIndex"),10),!isNaN(i)&&0!==i))return i;e=e.parent()}return 0}function n(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},e.extend(this._defaults,this.regional[""]),this.regional.en=e.extend(!0,{},this.regional[""]),this.regional["en-US"]=e.extend(!0,{},this.regional.en),this.dpDiv=a(e("<div id='"+this._mainDivId+"' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"))}function a(t){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return t.delegate(i,"mouseout",function(){e(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&e(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&e(this).removeClass("ui-datepicker-next-hover")}).delegate(i,"mouseover",o)}function o(){e.datepicker._isDisabledDatepicker(v.inline?v.dpDiv.parent()[0]:v.input[0])||(e(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),e(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&e(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&e(this).addClass("ui-datepicker-next-hover"))}function r(t,i){e.extend(t,i);for(var s in i)null==i[s]&&(t[s]=i[s]);return t}function h(e){return function(){var t=this.element.val();e.apply(this,arguments),this._refresh(),t!==this.element.val()&&this._trigger("change")}}e.ui=e.ui||{},e.extend(e.ui,{version:"1.11.4",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({scrollParent:function(t){var i=this.css("position"),s="absolute"===i,n=t?/(auto|scroll|hidden)/:/(auto|scroll)/,a=this.parents().filter(function(){var t=e(this);return s&&"static"===t.css("position")?!1:n.test(t.css("overflow")+t.css("overflow-y")+t.css("overflow-x"))}).eq(0);return"fixed"!==i&&a.length?a:e(this[0].ownerDocument||document)},uniqueId:function(){var e=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++e)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(i){return t(i,!isNaN(e.attr(i,"tabindex")))},tabbable:function(i){var s=e.attr(i,"tabindex"),n=isNaN(s);return(n||s>=0)&&t(i,!n)}}),e("<a>").outerWidth(1).jquery||e.each(["Width","Height"],function(t,i){function s(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],a=i.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+i]=function(t){return void 0===t?o["inner"+i].call(this):this.each(function(){e(this).css(a,s(this,t)+"px")})},e.fn["outer"+i]=function(t,n){return"number"!=typeof t?o["outer"+i].call(this,t):this.each(function(){e(this).css(a,s(this,t,!0,n)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),disableSelection:function(){var e="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.bind(e+".ui-disableSelection",function(e){e.preventDefault()})}}(),enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(t){if(void 0!==t)return this.css("zIndex",t);if(this.length)for(var i,s,n=e(this[0]);n.length&&n[0]!==document;){if(i=n.css("position"),("absolute"===i||"relative"===i||"fixed"===i)&&(s=parseInt(n.css("zIndex"),10),!isNaN(s)&&0!==s))return s;n=n.parent()}return 0}}),e.ui.plugin={add:function(t,i,s){var n,a=e.ui[t].prototype;for(n in s)a.plugins[n]=a.plugins[n]||[],a.plugins[n].push([i,s[n]])},call:function(e,t,i,s){var n,a=e.plugins[t];if(a&&(s||e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType))for(n=0;a.length>n;n++)e.options[a[n][0]]&&a[n][1].apply(e.element,i)}};var l=0,u=Array.prototype.slice;e.cleanData=function(t){return function(i){var s,n,a;for(a=0;null!=(n=i[a]);a++)try{s=e._data(n,"events"),s&&s.remove&&e(n).triggerHandler("remove")}catch(o){}t(i)}}(e.cleanData),e.widget=function(t,i,s){var n,a,o,r,h={},l=t.split(".")[0];return t=t.split(".")[1],n=l+"-"+t,s||(s=i,i=e.Widget),e.expr[":"][n.toLowerCase()]=function(t){return!!e.data(t,n)},e[l]=e[l]||{},a=e[l][t],o=e[l][t]=function(e,t){return this._createWidget?(arguments.length&&this._createWidget(e,t),void 0):new o(e,t)},e.extend(o,a,{version:s.version,_proto:e.extend({},s),_childConstructors:[]}),r=new i,r.options=e.widget.extend({},r.options),e.each(s,function(t,s){return e.isFunction(s)?(h[t]=function(){var e=function(){return i.prototype[t].apply(this,arguments)},n=function(e){return i.prototype[t].apply(this,e)};return function(){var t,i=this._super,a=this._superApply;return this._super=e,this._superApply=n,t=s.apply(this,arguments),this._super=i,this._superApply=a,t}}(),void 0):(h[t]=s,void 0)}),o.prototype=e.widget.extend(r,{widgetEventPrefix:a?r.widgetEventPrefix||t:t},h,{constructor:o,namespace:l,widgetName:t,widgetFullName:n}),a?(e.each(a._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete a._childConstructors):i._childConstructors.push(o),e.widget.bridge(t,o),o},e.widget.extend=function(t){for(var i,s,n=u.call(arguments,1),a=0,o=n.length;o>a;a++)for(i in n[a])s=n[a][i],n[a].hasOwnProperty(i)&&void 0!==s&&(t[i]=e.isPlainObject(s)?e.isPlainObject(t[i])?e.widget.extend({},t[i],s):e.widget.extend({},s):s);return t},e.widget.bridge=function(t,i){var s=i.prototype.widgetFullName||t;e.fn[t]=function(n){var a="string"==typeof n,o=u.call(arguments,1),r=this;return a?this.each(function(){var i,a=e.data(this,s);return"instance"===n?(r=a,!1):a?e.isFunction(a[n])&&"_"!==n.charAt(0)?(i=a[n].apply(a,o),i!==a&&void 0!==i?(r=i&&i.jquery?r.pushStack(i.get()):i,!1):void 0):e.error("no such method '"+n+"' for "+t+" widget instance"):e.error("cannot call methods on "+t+" prior to initialization; "+"attempted to call method '"+n+"'")}):(o.length&&(n=e.widget.extend.apply(null,[n].concat(o))),this.each(function(){var t=e.data(this,s);t?(t.option(n||{}),t._init&&t._init()):e.data(this,s,new i(n,this))})),r}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(t,i){i=e(i||this.defaultElement||this)[0],this.element=e(i),this.uuid=l++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=e(),this.hoverable=e(),this.focusable=e(),i!==this&&(e.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===i&&this.destroy()}}),this.document=e(i.style?i.ownerDocument:i.document||i),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(t,i){var s,n,a,o=t;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof t)if(o={},s=t.split("."),t=s.shift(),s.length){for(n=o[t]=e.widget.extend({},this.options[t]),a=0;s.length-1>a;a++)n[s[a]]=n[s[a]]||{},n=n[s[a]];if(t=s.pop(),1===arguments.length)return void 0===n[t]?null:n[t];n[t]=i}else{if(1===arguments.length)return void 0===this.options[t]?null:this.options[t];o[t]=i}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!t),t&&(this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus"))),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(t,i,s){var n,a=this;"boolean"!=typeof t&&(s=i,i=t,t=!1),s?(i=n=e(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),e.each(s,function(s,o){function r(){return t||a.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?a[o]:o).apply(a,arguments):void 0}"string"!=typeof o&&(r.guid=o.guid=o.guid||r.guid||e.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+a.eventNamespace,u=h[2];u?n.delegate(u,l,r):i.bind(l,r)})},_off:function(t,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(i).undelegate(i),this.bindings=e(this.bindings.not(t).get()),this.focusable=e(this.focusable.not(t).get()),this.hoverable=e(this.hoverable.not(t).get())},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,o=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(o)&&o.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var o,r=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),o=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),o&&e.effects&&e.effects.effect[r]?s[t](n):r!==t&&s[r]?s[r](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}}),e.widget;var d=!1;e(document).mouseup(function(){d=!1}),e.widget("ui.mouse",{version:"1.11.4",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(t){if(!d){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(t),this._mouseDownEvent=t;var i=this,s=1===t.which,n="string"==typeof this.options.cancel&&t.target.nodeName?e(t.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(t)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(t)!==!1,!this._mouseStarted)?(t.preventDefault(),!0):(!0===e.data(t.target,this.widgetName+".preventClickEvent")&&e.removeData(t.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return i._mouseMove(e)},this._mouseUpDelegate=function(e){return i._mouseUp(e)},this.document.bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),t.preventDefault(),d=!0,!0)):!0}},_mouseMove:function(t){if(this._mouseMoved){if(e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button)return this._mouseUp(t);if(!t.which)return this._mouseUp(t)}return(t.which||t.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),d=!1,!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),function(){function t(e,t,i){return[parseFloat(e[0])*(p.test(e[0])?t/100:1),parseFloat(e[1])*(p.test(e[1])?i/100:1)]}function i(t,i){return parseInt(e.css(t,i),10)||0}function s(t){var i=t[0];return 9===i.nodeType?{width:t.width(),height:t.height(),offset:{top:0,left:0}}:e.isWindow(i)?{width:t.width(),height:t.height(),offset:{top:t.scrollTop(),left:t.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:t.outerWidth(),height:t.outerHeight(),offset:t.offset()}}e.ui=e.ui||{};var n,a,o=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,u=/top|center|bottom/,d=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,p=/%$/,f=e.fn.position;e.position={scrollbarWidth:function(){if(void 0!==n)return n;var t,i,s=e("<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>"),a=s.children()[0];return e("body").append(s),t=a.offsetWidth,s.css("overflow","scroll"),i=a.offsetWidth,t===i&&(i=s[0].clientWidth),s.remove(),n=t-i},getScrollInfo:function(t){var i=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),s=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),n="scroll"===i||"auto"===i&&t.width<t.element[0].scrollWidth,a="scroll"===s||"auto"===s&&t.height<t.element[0].scrollHeight;return{width:a?e.position.scrollbarWidth():0,height:n?e.position.scrollbarWidth():0}},getWithinInfo:function(t){var i=e(t||window),s=e.isWindow(i[0]),n=!!i[0]&&9===i[0].nodeType;return{element:i,isWindow:s,isDocument:n,offset:i.offset()||{left:0,top:0},scrollLeft:i.scrollLeft(),scrollTop:i.scrollTop(),width:s||n?i.width():i.outerWidth(),height:s||n?i.height():i.outerHeight()}}},e.fn.position=function(n){if(!n||!n.of)return f.apply(this,arguments);n=e.extend({},n);var p,m,g,v,y,b,_=e(n.of),x=e.position.getWithinInfo(n.within),w=e.position.getScrollInfo(x),k=(n.collision||"flip").split(" "),T={};return b=s(_),_[0].preventDefault&&(n.at="left top"),m=b.width,g=b.height,v=b.offset,y=e.extend({},v),e.each(["my","at"],function(){var e,t,i=(n[this]||"").split(" ");1===i.length&&(i=l.test(i[0])?i.concat(["center"]):u.test(i[0])?["center"].concat(i):["center","center"]),i[0]=l.test(i[0])?i[0]:"center",i[1]=u.test(i[1])?i[1]:"center",e=d.exec(i[0]),t=d.exec(i[1]),T[this]=[e?e[0]:0,t?t[0]:0],n[this]=[c.exec(i[0])[0],c.exec(i[1])[0]]}),1===k.length&&(k[1]=k[0]),"right"===n.at[0]?y.left+=m:"center"===n.at[0]&&(y.left+=m/2),"bottom"===n.at[1]?y.top+=g:"center"===n.at[1]&&(y.top+=g/2),p=t(T.at,m,g),y.left+=p[0],y.top+=p[1],this.each(function(){var s,l,u=e(this),d=u.outerWidth(),c=u.outerHeight(),f=i(this,"marginLeft"),b=i(this,"marginTop"),D=d+f+i(this,"marginRight")+w.width,S=c+b+i(this,"marginBottom")+w.height,M=e.extend({},y),C=t(T.my,u.outerWidth(),u.outerHeight());"right"===n.my[0]?M.left-=d:"center"===n.my[0]&&(M.left-=d/2),"bottom"===n.my[1]?M.top-=c:"center"===n.my[1]&&(M.top-=c/2),M.left+=C[0],M.top+=C[1],a||(M.left=h(M.left),M.top=h(M.top)),s={marginLeft:f,marginTop:b},e.each(["left","top"],function(t,i){e.ui.position[k[t]]&&e.ui.position[k[t]][i](M,{targetWidth:m,targetHeight:g,elemWidth:d,elemHeight:c,collisionPosition:s,collisionWidth:D,collisionHeight:S,offset:[p[0]+C[0],p[1]+C[1]],my:n.my,at:n.at,within:x,elem:u})}),n.using&&(l=function(e){var t=v.left-M.left,i=t+m-d,s=v.top-M.top,a=s+g-c,h={target:{element:_,left:v.left,top:v.top,width:m,height:g},element:{element:u,left:M.left,top:M.top,width:d,height:c},horizontal:0>i?"left":t>0?"right":"center",vertical:0>a?"top":s>0?"bottom":"middle"};d>m&&m>r(t+i)&&(h.horizontal="center"),c>g&&g>r(s+a)&&(h.vertical="middle"),h.important=o(r(t),r(i))>o(r(s),r(a))?"horizontal":"vertical",n.using.call(this,e,h)}),u.offset(e.extend(M,{using:l}))})},e.ui.position={fit:{left:function(e,t){var i,s=t.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=e.left-t.collisionPosition.marginLeft,h=n-r,l=r+t.collisionWidth-a-n;t.collisionWidth>a?h>0&&0>=l?(i=e.left+h+t.collisionWidth-a-n,e.left+=h-i):e.left=l>0&&0>=h?n:h>l?n+a-t.collisionWidth:n:h>0?e.left+=h:l>0?e.left-=l:e.left=o(e.left-r,e.left)},top:function(e,t){var i,s=t.within,n=s.isWindow?s.scrollTop:s.offset.top,a=t.within.height,r=e.top-t.collisionPosition.marginTop,h=n-r,l=r+t.collisionHeight-a-n;t.collisionHeight>a?h>0&&0>=l?(i=e.top+h+t.collisionHeight-a-n,e.top+=h-i):e.top=l>0&&0>=h?n:h>l?n+a-t.collisionHeight:n:h>0?e.top+=h:l>0?e.top-=l:e.top=o(e.top-r,e.top)}},flip:{left:function(e,t){var i,s,n=t.within,a=n.offset.left+n.scrollLeft,o=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=e.left-t.collisionPosition.marginLeft,u=l-h,d=l+t.collisionWidth-o-h,c="left"===t.my[0]?-t.elemWidth:"right"===t.my[0]?t.elemWidth:0,p="left"===t.at[0]?t.targetWidth:"right"===t.at[0]?-t.targetWidth:0,f=-2*t.offset[0];0>u?(i=e.left+c+p+f+t.collisionWidth-o-a,(0>i||r(u)>i)&&(e.left+=c+p+f)):d>0&&(s=e.left-t.collisionPosition.marginLeft+c+p+f-h,(s>0||d>r(s))&&(e.left+=c+p+f))},top:function(e,t){var i,s,n=t.within,a=n.offset.top+n.scrollTop,o=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=e.top-t.collisionPosition.marginTop,u=l-h,d=l+t.collisionHeight-o-h,c="top"===t.my[1],p=c?-t.elemHeight:"bottom"===t.my[1]?t.elemHeight:0,f="top"===t.at[1]?t.targetHeight:"bottom"===t.at[1]?-t.targetHeight:0,m=-2*t.offset[1];0>u?(s=e.top+p+f+m+t.collisionHeight-o-a,(0>s||r(u)>s)&&(e.top+=p+f+m)):d>0&&(i=e.top-t.collisionPosition.marginTop+p+f+m-h,(i>0||d>r(i))&&(e.top+=p+f+m))}},flipfit:{left:function(){e.ui.position.flip.left.apply(this,arguments),e.ui.position.fit.left.apply(this,arguments)},top:function(){e.ui.position.flip.top.apply(this,arguments),e.ui.position.fit.top.apply(this,arguments)}}},function(){var t,i,s,n,o,r=document.getElementsByTagName("body")[0],h=document.createElement("div");t=document.createElement(r?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},r&&e.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(o in s)t.style[o]=s[o];t.appendChild(h),i=r||document.documentElement,i.insertBefore(t,i.firstChild),h.style.cssText="position: absolute; left: 10.7432222px;",n=e(h).offset().left,a=n>10&&11>n,t.innerHTML="",i.removeChild(t)}()}(),e.ui.position,e.widget("ui.draggable",e.ui.mouse,{version:"1.11.4",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"===this.options.helper&&this._setPositionRelative(),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._setHandleClassName(),this._mouseInit()},_setOption:function(e,t){this._super(e,t),"handle"===e&&(this._removeHandleClassName(),this._setHandleClassName())},_destroy:function(){return(this.helper||this.element).is(".ui-draggable-dragging")?(this.destroyOnClear=!0,void 0):(this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._removeHandleClassName(),this._mouseDestroy(),void 0)},_mouseCapture:function(t){var i=this.options;return this._blurActiveElement(t),this.helper||i.disabled||e(t.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(t),this.handle?(this._blockFrames(i.iframeFix===!0?"iframe":i.iframeFix),!0):!1)},_blockFrames:function(t){this.iframeBlocks=this.document.find(t).map(function(){var t=e(this);return e("<div>").css("position","absolute").appendTo(t.parent()).outerWidth(t.outerWidth()).outerHeight(t.outerHeight()).offset(t.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_blurActiveElement:function(t){var i=this.document[0];if(this.handleElement.is(t.target))try{i.activeElement&&"body"!==i.activeElement.nodeName.toLowerCase()&&e(i.activeElement).blur()}catch(s){}},_mouseStart:function(t){var i=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(!0),this.offsetParent=this.helper.offsetParent(),this.hasFixedAncestor=this.helper.parents().filter(function(){return"fixed"===e(this).css("position")}).length>0,this.positionAbs=this.element.offset(),this._refreshOffsets(t),this.originalPosition=this.position=this._generatePosition(t,!1),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._normalizeRightBottom(),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_refreshOffsets:function(e){this.offset={top:this.positionAbs.top-this.margins.top,left:this.positionAbs.left-this.margins.left,scroll:!1,parent:this._getParentOffset(),relative:this._getRelativeOffset()},this.offset.click={left:e.pageX-this.offset.left,top:e.pageY-this.offset.top}},_mouseDrag:function(t,i){if(this.hasFixedAncestor&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(t,!0),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",t,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.helper[0].style.left=this.position.left+"px",this.helper[0].style.top=this.position.top+"px",e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var i=this,s=!1;return e.ui.ddmanager&&!this.options.dropBehaviour&&(s=e.ui.ddmanager.drop(this,t)),this.dropped&&(s=this.dropped,this.dropped=!1),"invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",t)!==!1&&i._clear()}):this._trigger("stop",t)!==!1&&this._clear(),!1},_mouseUp:function(t){return this._unblockFrames(),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),this.handleElement.is(t.target)&&this.element.focus(),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){return this.options.handle?!!e(t.target).closest(this.element.find(this.options.handle)).length:!0},_setHandleClassName:function(){this.handleElement=this.options.handle?this.element.find(this.options.handle):this.element,this.handleElement.addClass("ui-draggable-handle")},_removeHandleClassName:function(){this.handleElement.removeClass("ui-draggable-handle")},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper),n=s?e(i.helper.apply(this.element[0],[t])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return n.parents("body").length||n.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s&&n[0]===this.element[0]&&this._setPositionRelative(),n[0]===this.element[0]||/(fixed|absolute)/.test(n.css("position"))||n.css("position","absolute"),n},_setPositionRelative:function(){/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative")},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_isRootNode:function(e){return/(html|body)/i.test(e.tagName)||e===this.document[0]},_getParentOffset:function(){var t=this.offsetParent.offset(),i=this.document[0];return"absolute"===this.cssPosition&&this.scrollParent[0]!==i&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),this._isRootNode(this.offsetParent[0])&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"!==this.cssPosition)return{top:0,left:0};var e=this.element.position(),t=this._isRootNode(this.scrollParent[0]);return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+(t?0:this.scrollParent.scrollTop()),left:e.left-(parseInt(this.helper.css("left"),10)||0)+(t?0:this.scrollParent.scrollLeft())}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options,a=this.document[0];return this.relativeContainer=null,n.containment?"window"===n.containment?(this.containment=[e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,e(window).scrollLeft()+e(window).width()-this.helperProportions.width-this.margins.left,e(window).scrollTop()+(e(window).height()||a.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===n.containment?(this.containment=[0,0,e(a).width()-this.helperProportions.width-this.margins.left,(e(a).height()||a.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):n.containment.constructor===Array?(this.containment=n.containment,void 0):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=e(n.containment),s=i[0],s&&(t=/(scroll|auto)/.test(i.css("overflow")),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(t?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(t?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relativeContainer=i),void 0):(this.containment=null,void 0)},_convertPositionTo:function(e,t){t||(t=this.position);var i="absolute"===e?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:t.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:t.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(e,t){var i,s,n,a,o=this.options,r=this._isRootNode(this.scrollParent[0]),h=e.pageX,l=e.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),t&&(this.containment&&(this.relativeContainer?(s=this.relativeContainer.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,e.pageX-this.offset.click.left<i[0]&&(h=i[0]+this.offset.click.left),e.pageY-this.offset.click.top<i[1]&&(l=i[1]+this.offset.click.top),e.pageX-this.offset.click.left>i[2]&&(h=i[2]+this.offset.click.left),e.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),o.grid&&(n=o.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-o.grid[1]:n+o.grid[1]:n,a=o.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX,h=i?a-this.offset.click.left>=i[0]||a-this.offset.click.left>i[2]?a:a-this.offset.click.left>=i[0]?a-o.grid[0]:a+o.grid[0]:a),"y"===o.axis&&(h=this.originalPageX),"x"===o.axis&&(l=this.originalPageY)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)}
+},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_normalizeRightBottom:function(){"y"!==this.options.axis&&"auto"!==this.helper.css("right")&&(this.helper.width(this.helper.width()),this.helper.css("right","auto")),"x"!==this.options.axis&&"auto"!==this.helper.css("bottom")&&(this.helper.height(this.helper.height()),this.helper.css("bottom","auto"))},_trigger:function(t,i,s){return s=s||this._uiHash(),e.ui.plugin.call(this,t,[i,s,this],!0),/^(drag|start|stop)/.test(t)&&(this.positionAbs=this._convertPositionTo("absolute"),s.offset=this.positionAbs),e.Widget.prototype._trigger.call(this,t,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),e.ui.plugin.add("draggable","connectToSortable",{start:function(t,i,s){var n=e.extend({},i,{item:s.element});s.sortables=[],e(s.options.connectToSortable).each(function(){var i=e(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push(i),i.refreshPositions(),i._trigger("activate",t,n))})},stop:function(t,i,s){var n=e.extend({},i,{item:s.element});s.cancelHelperRemoval=!1,e.each(s.sortables,function(){var e=this;e.isOver?(e.isOver=0,s.cancelHelperRemoval=!0,e.cancelHelperRemoval=!1,e._storedCSS={position:e.placeholder.css("position"),top:e.placeholder.css("top"),left:e.placeholder.css("left")},e._mouseStop(t),e.options.helper=e.options._helper):(e.cancelHelperRemoval=!0,e._trigger("deactivate",t,n))})},drag:function(t,i,s){e.each(s.sortables,function(){var n=!1,a=this;a.positionAbs=s.positionAbs,a.helperProportions=s.helperProportions,a.offset.click=s.offset.click,a._intersectsWith(a.containerCache)&&(n=!0,e.each(s.sortables,function(){return this.positionAbs=s.positionAbs,this.helperProportions=s.helperProportions,this.offset.click=s.offset.click,this!==a&&this._intersectsWith(this.containerCache)&&e.contains(a.element[0],this.element[0])&&(n=!1),n})),n?(a.isOver||(a.isOver=1,s._parent=i.helper.parent(),a.currentItem=i.helper.appendTo(a.element).data("ui-sortable-item",!0),a.options._helper=a.options.helper,a.options.helper=function(){return i.helper[0]},t.target=a.currentItem[0],a._mouseCapture(t,!0),a._mouseStart(t,!0,!0),a.offset.click.top=s.offset.click.top,a.offset.click.left=s.offset.click.left,a.offset.parent.left-=s.offset.parent.left-a.offset.parent.left,a.offset.parent.top-=s.offset.parent.top-a.offset.parent.top,s._trigger("toSortable",t),s.dropped=a.element,e.each(s.sortables,function(){this.refreshPositions()}),s.currentItem=s.element,a.fromOutside=s),a.currentItem&&(a._mouseDrag(t),i.position=a.position)):a.isOver&&(a.isOver=0,a.cancelHelperRemoval=!0,a.options._revert=a.options.revert,a.options.revert=!1,a._trigger("out",t,a._uiHash(a)),a._mouseStop(t,!0),a.options.revert=a.options._revert,a.options.helper=a.options._helper,a.placeholder&&a.placeholder.remove(),i.helper.appendTo(s._parent),s._refreshOffsets(t),i.position=s._generatePosition(t,!0),s._trigger("fromSortable",t),s.dropped=!1,e.each(s.sortables,function(){this.refreshPositions()}))})}}),e.ui.plugin.add("draggable","cursor",{start:function(t,i,s){var n=e("body"),a=s.options;n.css("cursor")&&(a._cursor=n.css("cursor")),n.css("cursor",a.cursor)},stop:function(t,i,s){var n=s.options;n._cursor&&e("body").css("cursor",n._cursor)}}),e.ui.plugin.add("draggable","opacity",{start:function(t,i,s){var n=e(i.helper),a=s.options;n.css("opacity")&&(a._opacity=n.css("opacity")),n.css("opacity",a.opacity)},stop:function(t,i,s){var n=s.options;n._opacity&&e(i.helper).css("opacity",n._opacity)}}),e.ui.plugin.add("draggable","scroll",{start:function(e,t,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(t,i,s){var n=s.options,a=!1,o=s.scrollParentNotHidden[0],r=s.document[0];o!==r&&"HTML"!==o.tagName?(n.axis&&"x"===n.axis||(s.overflowOffset.top+o.offsetHeight-t.pageY<n.scrollSensitivity?o.scrollTop=a=o.scrollTop+n.scrollSpeed:t.pageY-s.overflowOffset.top<n.scrollSensitivity&&(o.scrollTop=a=o.scrollTop-n.scrollSpeed)),n.axis&&"y"===n.axis||(s.overflowOffset.left+o.offsetWidth-t.pageX<n.scrollSensitivity?o.scrollLeft=a=o.scrollLeft+n.scrollSpeed:t.pageX-s.overflowOffset.left<n.scrollSensitivity&&(o.scrollLeft=a=o.scrollLeft-n.scrollSpeed))):(n.axis&&"x"===n.axis||(t.pageY-e(r).scrollTop()<n.scrollSensitivity?a=e(r).scrollTop(e(r).scrollTop()-n.scrollSpeed):e(window).height()-(t.pageY-e(r).scrollTop())<n.scrollSensitivity&&(a=e(r).scrollTop(e(r).scrollTop()+n.scrollSpeed))),n.axis&&"y"===n.axis||(t.pageX-e(r).scrollLeft()<n.scrollSensitivity?a=e(r).scrollLeft(e(r).scrollLeft()-n.scrollSpeed):e(window).width()-(t.pageX-e(r).scrollLeft())<n.scrollSensitivity&&(a=e(r).scrollLeft(e(r).scrollLeft()+n.scrollSpeed)))),a!==!1&&e.ui.ddmanager&&!n.dropBehaviour&&e.ui.ddmanager.prepareOffsets(s,t)}}),e.ui.plugin.add("draggable","snap",{start:function(t,i,s){var n=s.options;s.snapElements=[],e(n.snap.constructor!==String?n.snap.items||":data(ui-draggable)":n.snap).each(function(){var t=e(this),i=t.offset();this!==s.element[0]&&s.snapElements.push({item:this,width:t.outerWidth(),height:t.outerHeight(),top:i.top,left:i.left})})},drag:function(t,i,s){var n,a,o,r,h,l,u,d,c,p,f=s.options,m=f.snapTolerance,g=i.offset.left,v=g+s.helperProportions.width,y=i.offset.top,b=y+s.helperProportions.height;for(c=s.snapElements.length-1;c>=0;c--)h=s.snapElements[c].left-s.margins.left,l=h+s.snapElements[c].width,u=s.snapElements[c].top-s.margins.top,d=u+s.snapElements[c].height,h-m>v||g>l+m||u-m>b||y>d+m||!e.contains(s.snapElements[c].item.ownerDocument,s.snapElements[c].item)?(s.snapElements[c].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,t,e.extend(s._uiHash(),{snapItem:s.snapElements[c].item})),s.snapElements[c].snapping=!1):("inner"!==f.snapMode&&(n=m>=Math.abs(u-b),a=m>=Math.abs(d-y),o=m>=Math.abs(h-v),r=m>=Math.abs(l-g),n&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top),a&&(i.position.top=s._convertPositionTo("relative",{top:d,left:0}).top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left)),p=n||a||o||r,"outer"!==f.snapMode&&(n=m>=Math.abs(u-y),a=m>=Math.abs(d-b),o=m>=Math.abs(h-g),r=m>=Math.abs(l-v),n&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top),a&&(i.position.top=s._convertPositionTo("relative",{top:d-s.helperProportions.height,left:0}).top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left)),!s.snapElements[c].snapping&&(n||a||o||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,t,e.extend(s._uiHash(),{snapItem:s.snapElements[c].item})),s.snapElements[c].snapping=n||a||o||r||p)}}),e.ui.plugin.add("draggable","stack",{start:function(t,i,s){var n,a=s.options,o=e.makeArray(e(a.stack)).sort(function(t,i){return(parseInt(e(t).css("zIndex"),10)||0)-(parseInt(e(i).css("zIndex"),10)||0)});o.length&&(n=parseInt(e(o[0]).css("zIndex"),10)||0,e(o).each(function(t){e(this).css("zIndex",n+t)}),this.css("zIndex",n+o.length))}}),e.ui.plugin.add("draggable","zIndex",{start:function(t,i,s){var n=e(i.helper),a=s.options;n.css("zIndex")&&(a._zIndex=n.css("zIndex")),n.css("zIndex",a.zIndex)},stop:function(t,i,s){var n=s.options;n._zIndex&&e(i.helper).css("zIndex",n._zIndex)}}),e.ui.draggable,e.widget("ui.droppable",{version:"1.11.4",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var t,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=e.isFunction(s)?s:function(e){return e.is(s)},this.proportions=function(){return arguments.length?(t=arguments[0],void 0):t?t:t={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},this._addToManager(i.scope),i.addClasses&&this.element.addClass("ui-droppable")},_addToManager:function(t){e.ui.ddmanager.droppables[t]=e.ui.ddmanager.droppables[t]||[],e.ui.ddmanager.droppables[t].push(this)},_splice:function(e){for(var t=0;e.length>t;t++)e[t]===this&&e.splice(t,1)},_destroy:function(){var t=e.ui.ddmanager.droppables[this.options.scope];this._splice(t),this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(t,i){if("accept"===t)this.accept=e.isFunction(i)?i:function(e){return e.is(i)};else if("scope"===t){var s=e.ui.ddmanager.droppables[this.options.scope];this._splice(s),this._addToManager(i)}this._super(t,i)},_activate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",t,this.ui(i))},_deactivate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",t,this.ui(i))},_over:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",t,this.ui(i)))},_out:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",t,this.ui(i)))},_drop:function(t,i){var s=i||e.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var i=e(this).droppable("instance");return i.options.greedy&&!i.options.disabled&&i.options.scope===s.options.scope&&i.accept.call(i.element[0],s.currentItem||s.element)&&e.ui.intersect(s,e.extend(i,{offset:i.element.offset()}),i.options.tolerance,t)?(n=!0,!1):void 0}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",t,this.ui(s)),this.element):!1):!1},ui:function(e){return{draggable:e.currentItem||e.element,helper:e.helper,position:e.position,offset:e.positionAbs}}}),e.ui.intersect=function(){function e(e,t,i){return e>=t&&t+i>e}return function(t,i,s,n){if(!i.offset)return!1;var a=(t.positionAbs||t.position.absolute).left+t.margins.left,o=(t.positionAbs||t.position.absolute).top+t.margins.top,r=a+t.helperProportions.width,h=o+t.helperProportions.height,l=i.offset.left,u=i.offset.top,d=l+i.proportions().width,c=u+i.proportions().height;switch(s){case"fit":return a>=l&&d>=r&&o>=u&&c>=h;case"intersect":return a+t.helperProportions.width/2>l&&d>r-t.helperProportions.width/2&&o+t.helperProportions.height/2>u&&c>h-t.helperProportions.height/2;case"pointer":return e(n.pageY,u,i.proportions().height)&&e(n.pageX,l,i.proportions().width);case"touch":return(o>=u&&c>=o||h>=u&&c>=h||u>o&&h>c)&&(a>=l&&d>=a||r>=l&&d>=r||l>a&&r>d);default:return!1}}}(),e.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,i){var s,n,a=e.ui.ddmanager.droppables[t.options.scope]||[],o=i?i.type:null,r=(t.currentItem||t.element).find(":data(ui-droppable)").addBack();e:for(s=0;a.length>s;s++)if(!(a[s].options.disabled||t&&!a[s].accept.call(a[s].element[0],t.currentItem||t.element))){for(n=0;r.length>n;n++)if(r[n]===a[s].element[0]){a[s].proportions().height=0;continue e}a[s].visible="none"!==a[s].element.css("display"),a[s].visible&&("mousedown"===o&&a[s]._activate.call(a[s],i),a[s].offset=a[s].element.offset(),a[s].proportions({width:a[s].element[0].offsetWidth,height:a[s].element[0].offsetHeight}))}},drop:function(t,i){var s=!1;return e.each((e.ui.ddmanager.droppables[t.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&e.ui.intersect(t,this,this.options.tolerance,i)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],t.currentItem||t.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(t,i){t.element.parentsUntil("body").bind("scroll.droppable",function(){t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)})},drag:function(t,i){t.options.refreshPositions&&e.ui.ddmanager.prepareOffsets(t,i),e.each(e.ui.ddmanager.droppables[t.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,a,o=e.ui.intersect(t,this,this.options.tolerance,i),r=!o&&this.isover?"isout":o&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,a=this.element.parents(":data(ui-droppable)").filter(function(){return e(this).droppable("instance").options.scope===n}),a.length&&(s=e(a[0]).droppable("instance"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(t,i){t.element.parentsUntil("body").unbind("scroll.droppable"),t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)}},e.ui.droppable,e.widget("ui.resizable",e.ui.mouse,{version:"1.11.4",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(e){return parseInt(e,10)||0},_isNumber:function(e){return!isNaN(parseInt(e,10))},_hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return t[s]>0?!0:(t[s]=1,n=t[s]>0,t[s]=0,n)},_create:function(){var t,i,s,n,a,o=this,r=this.options;if(this.element.addClass("ui-resizable"),e.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(e("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=e(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),t=this.handles.split(","),this.handles={},i=0;t.length>i;i++)s=e.trim(t[i]),a="ui-resizable-"+s,n=e("<div class='ui-resizable-handle "+a+"'></div>"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(t){var i,s,n,a;t=t||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=e(this.handles[i]),this._on(this.handles[i],{mousedown:o._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=e(this.handles[i],this.element),a=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),t.css(n,a),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.mouseover(function(){o.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),o.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(e(this).removeClass("ui-resizable-autohide"),o._handles.show())}).mouseleave(function(){r.disabled||o.resizing||(e(this).addClass("ui-resizable-autohide"),o._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t,i=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),t=this.element,this.originalElement.css({position:t.css("position"),width:t.outerWidth(),height:t.outerHeight(),top:t.css("top"),left:t.css("left")}).insertAfter(t),t.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(t){var i,s,n=!1;for(i in this.handles)s=e(this.handles[i])[0],(s===t.target||e.contains(s,t.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(t){var i,s,n,a=this.options,o=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),a.containment&&(i+=e(a.containment).scrollLeft()||0,s+=e(a.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:o.width(),height:o.height()},this.originalSize=this._helper?{width:o.outerWidth(),height:o.outerHeight()}:{width:o.width(),height:o.height()},this.sizeDiff={width:o.outerWidth()-o.width(),height:o.outerHeight()-o.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio="number"==typeof a.aspectRatio?a.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=e(".ui-resizable-"+this.axis).css("cursor"),e("body").css("cursor","auto"===n?this.axis+"-resize":n),o.addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(t){var i,s,n=this.originalMousePosition,a=this.axis,o=t.pageX-n.left||0,r=t.pageY-n.top||0,h=this._change[a];return this._updatePrevProperties(),h?(i=h.apply(this,[t,o,r]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(i=this._updateRatio(i,t)),i=this._respectSize(i,t),this._updateCache(i),this._propagate("resize",t),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),e.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",t,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(t){this.resizing=!1;var i,s,n,a,o,r,h,l=this.options,u=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:u.sizeDiff.height,a=s?0:u.sizeDiff.width,o={width:u.helper.width()-a,height:u.helper.height()-n},r=parseInt(u.element.css("left"),10)+(u.position.left-u.originalPosition.left)||null,h=parseInt(u.element.css("top"),10)+(u.position.top-u.originalPosition.top)||null,l.animate||this.element.css(e.extend(o,{top:h,left:r})),u.helper.height(u.size.height),u.helper.width(u.size.width),this._helper&&!l.animate&&this._proportionallyResize()),e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var e={};return this.position.top!==this.prevPosition.top&&(e.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(e.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(e.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(e.height=this.size.height+"px"),this.helper.css(e),e},_updateVirtualBoundaries:function(e){var t,i,s,n,a,o=this.options;a={minWidth:this._isNumber(o.minWidth)?o.minWidth:0,maxWidth:this._isNumber(o.maxWidth)?o.maxWidth:1/0,minHeight:this._isNumber(o.minHeight)?o.minHeight:0,maxHeight:this._isNumber(o.maxHeight)?o.maxHeight:1/0},(this._aspectRatio||e)&&(t=a.minHeight*this.aspectRatio,s=a.minWidth/this.aspectRatio,i=a.maxHeight*this.aspectRatio,n=a.maxWidth/this.aspectRatio,t>a.minWidth&&(a.minWidth=t),s>a.minHeight&&(a.minHeight=s),a.maxWidth>i&&(a.maxWidth=i),a.maxHeight>n&&(a.maxHeight=n)),this._vBoundaries=a},_updateCache:function(e){this.offset=this.helper.offset(),this._isNumber(e.left)&&(this.position.left=e.left),this._isNumber(e.top)&&(this.position.top=e.top),this._isNumber(e.height)&&(this.size.height=e.height),this._isNumber(e.width)&&(this.size.width=e.width)},_updateRatio:function(e){var t=this.position,i=this.size,s=this.axis;return this._isNumber(e.height)?e.width=e.height*this.aspectRatio:this._isNumber(e.width)&&(e.height=e.width/this.aspectRatio),"sw"===s&&(e.left=t.left+(i.width-e.width),e.top=null),"nw"===s&&(e.top=t.top+(i.height-e.height),e.left=t.left+(i.width-e.width)),e},_respectSize:function(e){var t=this._vBoundaries,i=this.axis,s=this._isNumber(e.width)&&t.maxWidth&&t.maxWidth<e.width,n=this._isNumber(e.height)&&t.maxHeight&&t.maxHeight<e.height,a=this._isNumber(e.width)&&t.minWidth&&t.minWidth>e.width,o=this._isNumber(e.height)&&t.minHeight&&t.minHeight>e.height,r=this.originalPosition.left+this.originalSize.width,h=this.position.top+this.size.height,l=/sw|nw|w/.test(i),u=/nw|ne|n/.test(i);return a&&(e.width=t.minWidth),o&&(e.height=t.minHeight),s&&(e.width=t.maxWidth),n&&(e.height=t.maxHeight),a&&l&&(e.left=r-t.minWidth),s&&l&&(e.left=r-t.maxWidth),o&&u&&(e.top=h-t.minHeight),n&&u&&(e.top=h-t.maxHeight),e.width||e.height||e.left||!e.top?e.width||e.height||e.top||!e.left||(e.left=null):e.top=null,e},_getPaddingPlusBorderDimensions:function(e){for(var t=0,i=[],s=[e.css("borderTopWidth"),e.css("borderRightWidth"),e.css("borderBottomWidth"),e.css("borderLeftWidth")],n=[e.css("paddingTop"),e.css("paddingRight"),e.css("paddingBottom"),e.css("paddingLeft")];4>t;t++)i[t]=parseInt(s[t],10)||0,i[t]+=parseInt(n[t],10)||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var e,t=0,i=this.helper||this.element;this._proportionallyResizeElements.length>t;t++)e=this._proportionallyResizeElements[t],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(e)),e.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var t=this.element,i=this.options;this.elementOffset=t.offset(),this._helper?(this.helper=this.helper||e("<div style='overflow:hidden;'></div>"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(e,t){return{width:this.originalSize.width+t}},w:function(e,t){var i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(e,t,i){return{height:this.originalSize.height+i}},se:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},sw:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,i,s]))},ne:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},nw:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,i,s]))}},_propagate:function(t,i){e.ui.plugin.call(this,t,[i,this.ui()]),"resize"!==t&&this._trigger(t,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","animate",{stop:function(t){var i=e(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,a=n.length&&/textarea/i.test(n[0].nodeName),o=a&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=a?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-o},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,u=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(e.extend(h,u&&l?{top:u,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&e(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(){var t,i,s,n,a,o,r,h=e(this).resizable("instance"),l=h.options,u=h.element,d=l.containment,c=d instanceof e?d.get(0):/parent/.test(d)?u.parent().get(0):d;c&&(h.containerElement=e(c),/document/.test(d)||d===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}):(t=e(c),i=[],e(["Top","Right","Left","Bottom"]).each(function(e,s){i[e]=h._num(t.css("padding"+s))}),h.containerOffset=t.offset(),h.containerPosition=t.position(),h.containerSize={height:t.innerHeight()-i[3],width:t.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,a=h.containerSize.width,o=h._hasScroll(c,"left")?c.scrollWidth:a,r=h._hasScroll(c)?c.scrollHeight:n,h.parentData={element:c,left:s.left,top:s.top,width:o,height:r}))},resize:function(t){var i,s,n,a,o=e(this).resizable("instance"),r=o.options,h=o.containerOffset,l=o.position,u=o._aspectRatio||t.shiftKey,d={top:0,left:0},c=o.containerElement,p=!0;c[0]!==document&&/static/.test(c.css("position"))&&(d=h),l.left<(o._helper?h.left:0)&&(o.size.width=o.size.width+(o._helper?o.position.left-h.left:o.position.left-d.left),u&&(o.size.height=o.size.width/o.aspectRatio,p=!1),o.position.left=r.helper?h.left:0),l.top<(o._helper?h.top:0)&&(o.size.height=o.size.height+(o._helper?o.position.top-h.top:o.position.top),u&&(o.size.width=o.size.height*o.aspectRatio,p=!1),o.position.top=o._helper?h.top:0),n=o.containerElement.get(0)===o.element.parent().get(0),a=/relative|absolute/.test(o.containerElement.css("position")),n&&a?(o.offset.left=o.parentData.left+o.position.left,o.offset.top=o.parentData.top+o.position.top):(o.offset.left=o.element.offset().left,o.offset.top=o.element.offset().top),i=Math.abs(o.sizeDiff.width+(o._helper?o.offset.left-d.left:o.offset.left-h.left)),s=Math.abs(o.sizeDiff.height+(o._helper?o.offset.top-d.top:o.offset.top-h.top)),i+o.size.width>=o.parentData.width&&(o.size.width=o.parentData.width-i,u&&(o.size.height=o.size.width/o.aspectRatio,p=!1)),s+o.size.height>=o.parentData.height&&(o.size.height=o.parentData.height-s,u&&(o.size.width=o.size.height*o.aspectRatio,p=!1)),p||(o.position.left=o.prevPosition.left,o.position.top=o.prevPosition.top,o.size.width=o.prevSize.width,o.size.height=o.prevSize.height)},stop:function(){var t=e(this).resizable("instance"),i=t.options,s=t.containerOffset,n=t.containerPosition,a=t.containerElement,o=e(t.helper),r=o.offset(),h=o.outerWidth()-t.sizeDiff.width,l=o.outerHeight()-t.sizeDiff.height;t._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l}),t._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),e.ui.plugin.add("resizable","alsoResize",{start:function(){var t=e(this).resizable("instance"),i=t.options;e(i.alsoResize).each(function(){var t=e(this);t.data("ui-resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})},resize:function(t,i){var s=e(this).resizable("instance"),n=s.options,a=s.originalSize,o=s.originalPosition,r={height:s.size.height-a.height||0,width:s.size.width-a.width||0,top:s.position.top-o.top||0,left:s.position.left-o.left||0};e(n.alsoResize).each(function(){var t=e(this),s=e(this).data("ui-resizable-alsoresize"),n={},a=t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(a,function(e,t){var i=(s[t]||0)+(r[t]||0);i&&i>=0&&(n[t]=i||null)}),t.css(n)})},stop:function(){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","ghost",{start:function(){var t=e(this).resizable("instance"),i=t.options,s=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),t.ghost.appendTo(t.helper)},resize:function(){var t=e(this).resizable("instance");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=e(this).resizable("instance");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(){var t,i=e(this).resizable("instance"),s=i.options,n=i.size,a=i.originalSize,o=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,u=h[1]||1,d=Math.round((n.width-a.width)/l)*l,c=Math.round((n.height-a.height)/u)*u,p=a.width+d,f=a.height+c,m=s.maxWidth&&p>s.maxWidth,g=s.maxHeight&&f>s.maxHeight,v=s.minWidth&&s.minWidth>p,y=s.minHeight&&s.minHeight>f;s.grid=h,v&&(p+=l),y&&(f+=u),m&&(p-=l),g&&(f-=u),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=o.top-c):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=o.left-d):((0>=f-u||0>=p-l)&&(t=i._getPaddingPlusBorderDimensions(this)),f-u>0?(i.size.height=f,i.position.top=o.top-c):(f=u-t.height,i.size.height=f,i.position.top=o.top+a.height-f),p-l>0?(i.size.width=p,i.position.left=o.left-d):(p=l-t.width,i.size.width=p,i.position.left=o.left+a.width-p))}}),e.ui.resizable,e.widget("ui.selectable",e.ui.mouse,{version:"1.11.4",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var t,i=this;
+this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){t=e(i.options.filter,i.element[0]),t.addClass("ui-selectee"),t.each(function(){var t=e(this),i=t.offset();e.data(this,"selectable-item",{element:this,$element:t,left:i.left,top:i.top,right:i.left+t.outerWidth(),bottom:i.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=t.addClass("ui-selectee"),this._mouseInit(),this.helper=e("<div class='ui-selectable-helper'></div>")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(t){var i=this,s=this.options;this.opos=[t.pageX,t.pageY],this.options.disabled||(this.selectees=e(s.filter,this.element[0]),this._trigger("start",t),e(s.appendTo).append(this.helper),this.helper.css({left:t.pageX,top:t.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=e.data(this,"selectable-item");s.startselected=!0,t.metaKey||t.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",t,{unselecting:s.element}))}),e(t.target).parents().addBack().each(function(){var s,n=e.data(this,"selectable-item");return n?(s=!t.metaKey&&!t.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",t,{selecting:n.element}):i._trigger("unselecting",t,{unselecting:n.element}),!1):void 0}))},_mouseDrag:function(t){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,a=this.opos[0],o=this.opos[1],r=t.pageX,h=t.pageY;return a>r&&(i=r,r=a,a=i),o>h&&(i=h,h=o,o=i),this.helper.css({left:a,top:o,width:r-a,height:h-o}),this.selectees.each(function(){var i=e.data(this,"selectable-item"),l=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?l=!(i.left>r||a>i.right||i.top>h||o>i.bottom):"fit"===n.tolerance&&(l=i.left>a&&r>i.right&&i.top>o&&h>i.bottom),l?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",t,{selecting:i.element}))):(i.selecting&&((t.metaKey||t.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",t,{unselecting:i.element}))),i.selected&&(t.metaKey||t.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",t,{unselecting:i.element})))))}),!1}},_mouseStop:function(t){var i=this;return this.dragged=!1,e(".ui-unselecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",t,{unselected:s.element})}),e(".ui-selecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",t,{selected:s.element})}),this._trigger("stop",t),this.helper.remove(),!1}}),e.widget("ui.sortable",e.ui.mouse,{version:"1.11.4",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(e,t,i){return e>=t&&t+i>e},_isFloating:function(e){return/left|right/.test(e.css("float"))||/inline|table-cell/.test(e.css("display"))},_create:function(){this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.offset=this.element.offset(),this._mouseInit(),this._setHandleClassName(),this.ready=!0},_setOption:function(e,t){this._super(e,t),"handle"===e&&this._setHandleClassName()},_setHandleClassName:function(){this.element.find(".ui-sortable-handle").removeClass("ui-sortable-handle"),e.each(this.items,function(){(this.instance.options.handle?this.item.find(this.instance.options.handle):this.item).addClass("ui-sortable-handle")})},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").find(".ui-sortable-handle").removeClass("ui-sortable-handle"),this._mouseDestroy();for(var e=this.items.length-1;e>=0;e--)this.items[e].item.removeData(this.widgetName+"-item");return this},_mouseCapture:function(t,i){var s=null,n=!1,a=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(t),e(t.target).parents().each(function(){return e.data(this,a.widgetName+"-item")===a?(s=e(this),!1):void 0}),e.data(t.target,a.widgetName+"-item")===a&&(s=e(t.target)),s?!this.options.handle||i||(e(this.options.handle,s).find("*").addBack().each(function(){this===t.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(t,i,s){var n,a,o=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(t),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,o.cursorAt&&this._adjustOffsetFromHelper(o.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),o.containment&&this._setContainment(),o.cursor&&"auto"!==o.cursor&&(a=this.document.find("body"),this.storedCursor=a.css("cursor"),a.css("cursor",o.cursor),this.storedStylesheet=e("<style>*{ cursor: "+o.cursor+" !important; }</style>").appendTo(a)),o.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",o.opacity)),o.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",o.zIndex)),this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",t,this._uiHash(this));return e.ui.ddmanager&&(e.ui.ddmanager.current=this),e.ui.ddmanager&&!o.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(t),!0},_mouseDrag:function(t){var i,s,n,a,o=this.options,r=!1;for(this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageY<o.scrollSensitivity?this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop+o.scrollSpeed:t.pageY-this.overflowOffset.top<o.scrollSensitivity&&(this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop-o.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-t.pageX<o.scrollSensitivity?this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft+o.scrollSpeed:t.pageX-this.overflowOffset.left<o.scrollSensitivity&&(this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft-o.scrollSpeed)):(t.pageY-this.document.scrollTop()<o.scrollSensitivity?r=this.document.scrollTop(this.document.scrollTop()-o.scrollSpeed):this.window.height()-(t.pageY-this.document.scrollTop())<o.scrollSensitivity&&(r=this.document.scrollTop(this.document.scrollTop()+o.scrollSpeed)),t.pageX-this.document.scrollLeft()<o.scrollSensitivity?r=this.document.scrollLeft(this.document.scrollLeft()-o.scrollSpeed):this.window.width()-(t.pageX-this.document.scrollLeft())<o.scrollSensitivity&&(r=this.document.scrollLeft(this.document.scrollLeft()+o.scrollSpeed))),r!==!1&&e.ui.ddmanager&&!o.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t)),this.positionAbs=this._convertPositionTo("absolute"),this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),i=this.items.length-1;i>=0;i--)if(s=this.items[i],n=s.item[0],a=this._intersectsWithPointer(s),a&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===a?"next":"prev"]()[0]!==n&&!e.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!e.contains(this.element[0],n):!0)){if(this.direction=1===a?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(t,s),this._trigger("change",t,this._uiHash());break}return this._contactContainers(t),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),this._trigger("sort",t,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(t,i){if(t){if(e.ui.ddmanager&&!this.options.dropBehaviour&&e.ui.ddmanager.drop(this,t),this.options.revert){var s=this,n=this.placeholder.offset(),a=this.options.axis,o={};a&&"x"!==a||(o.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollLeft)),a&&"y"!==a||(o.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,e(this.helper).animate(o,parseInt(this.options.revert,10)||500,function(){s._clear(t)})}else this._clear(t,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var t=this.containers.length-1;t>=0;t--)this.containers[t]._trigger("deactivate",null,this._uiHash(this)),this.containers[t].containerCache.over&&(this.containers[t]._trigger("out",null,this._uiHash(this)),this.containers[t].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),e.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?e(this.domPosition.prev).after(this.currentItem):e(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},e(i).each(function(){var i=(e(t.item||this).attr(t.attribute||"id")||"").match(t.expression||/(.+)[\-=_](.+)/);i&&s.push((t.key||i[1]+"[]")+"="+(t.key&&t.expression?i[1]:i[2]))}),!s.length&&t.key&&s.push(t.key+"="),s.join("&")},toArray:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},i.each(function(){s.push(e(t.item||this).attr(t.attribute||"id")||"")}),s},_intersectsWith:function(e){var t=this.positionAbs.left,i=t+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,a=e.left,o=a+e.width,r=e.top,h=r+e.height,l=this.offset.click.top,u=this.offset.click.left,d="x"===this.options.axis||s+l>r&&h>s+l,c="y"===this.options.axis||t+u>a&&o>t+u,p=d&&c;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>e[this.floating?"width":"height"]?p:t+this.helperProportions.width/2>a&&o>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(e){var t="x"===this.options.axis||this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top,e.height),i="y"===this.options.axis||this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left,e.width),s=t&&i,n=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return s?this.floating?a&&"right"===a||"down"===n?2:1:n&&("down"===n?2:1):!1},_intersectsWithSides:function(e){var t=this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top+e.height/2,e.height),i=this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left+e.width/2,e.width),s=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&i||"left"===n&&!i:s&&("down"===s&&t||"up"===s&&!t)},_getDragVerticalDirection:function(){var e=this.positionAbs.top-this.lastPositionAbs.top;return 0!==e&&(e>0?"down":"up")},_getDragHorizontalDirection:function(){var e=this.positionAbs.left-this.lastPositionAbs.left;return 0!==e&&(e>0?"right":"left")},refresh:function(e){return this._refreshItems(e),this._setHandleClassName(),this.refreshPositions(),this},_connectWith:function(){var e=this.options;return e.connectWith.constructor===String?[e.connectWith]:e.connectWith},_getItemsAsjQuery:function(t){function i(){r.push(this)}var s,n,a,o,r=[],h=[],l=this._connectWith();if(l&&t)for(s=l.length-1;s>=0;s--)for(a=e(l[s],this.document[0]),n=a.length-1;n>=0;n--)o=e.data(a[n],this.widgetFullName),o&&o!==this&&!o.options.disabled&&h.push([e.isFunction(o.options.items)?o.options.items.call(o.element):e(o.options.items,o.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),o]);for(h.push([e.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):e(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=h.length-1;s>=0;s--)h[s][0].each(i);return e(r)},_removeCurrentsFromItems:function(){var t=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=e.grep(this.items,function(e){for(var i=0;t.length>i;i++)if(t[i]===e.item[0])return!1;return!0})},_refreshItems:function(t){this.items=[],this.containers=[this];var i,s,n,a,o,r,h,l,u=this.items,d=[[e.isFunction(this.options.items)?this.options.items.call(this.element[0],t,{item:this.currentItem}):e(this.options.items,this.element),this]],c=this._connectWith();if(c&&this.ready)for(i=c.length-1;i>=0;i--)for(n=e(c[i],this.document[0]),s=n.length-1;s>=0;s--)a=e.data(n[s],this.widgetFullName),a&&a!==this&&!a.options.disabled&&(d.push([e.isFunction(a.options.items)?a.options.items.call(a.element[0],t,{item:this.currentItem}):e(a.options.items,a.element),a]),this.containers.push(a));for(i=d.length-1;i>=0;i--)for(o=d[i][1],r=d[i][0],s=0,l=r.length;l>s;s++)h=e(r[s]),h.data(this.widgetName+"-item",o),u.push({item:h,instance:o,width:0,height:0,left:0,top:0})},refreshPositions:function(t){this.floating=this.items.length?"x"===this.options.axis||this._isFloating(this.items[0].item):!1,this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,a;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?e(this.options.toleranceElement,s.item):s.item,t||(s.width=n.outerWidth(),s.height=n.outerHeight()),a=n.offset(),s.left=a.left,s.top=a.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)a=this.containers[i].element.offset(),this.containers[i].containerCache.left=a.left,this.containers[i].containerCache.top=a.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(t){t=t||this;var i,s=t.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=t.currentItem[0].nodeName.toLowerCase(),n=e("<"+s+">",t.document[0]).addClass(i||t.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tbody"===s?t._createTrPlaceholder(t.currentItem.find("tr").eq(0),e("<tr>",t.document[0]).appendTo(n)):"tr"===s?t._createTrPlaceholder(t.currentItem,n):"img"===s&&n.attr("src",t.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(e,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(t.currentItem.innerHeight()-parseInt(t.currentItem.css("paddingTop")||0,10)-parseInt(t.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(t.currentItem.innerWidth()-parseInt(t.currentItem.css("paddingLeft")||0,10)-parseInt(t.currentItem.css("paddingRight")||0,10)))}}),t.placeholder=e(s.placeholder.element.call(t.element,t.currentItem)),t.currentItem.after(t.placeholder),s.placeholder.update(t,t.placeholder)},_createTrPlaceholder:function(t,i){var s=this;t.children().each(function(){e("<td>&#160;</td>",s.document[0]).attr("colspan",e(this).attr("colspan")||1).appendTo(i)})},_contactContainers:function(t){var i,s,n,a,o,r,h,l,u,d,c=null,p=null;for(i=this.containers.length-1;i>=0;i--)if(!e.contains(this.currentItem[0],this.containers[i].element[0]))if(this._intersectsWith(this.containers[i].containerCache)){if(c&&e.contains(this.containers[i].element[0],c.element[0]))continue;c=this.containers[i],p=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",t,this._uiHash(this)),this.containers[i].containerCache.over=0);if(c)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(n=1e4,a=null,u=c.floating||this._isFloating(this.currentItem),o=u?"left":"top",r=u?"width":"height",d=u?"clientX":"clientY",s=this.items.length-1;s>=0;s--)e.contains(this.containers[p].element[0],this.items[s].item[0])&&this.items[s].item[0]!==this.currentItem[0]&&(h=this.items[s].item.offset()[o],l=!1,t[d]-h>this.items[s][r]/2&&(l=!0),n>Math.abs(t[d]-h)&&(n=Math.abs(t[d]-h),a=this.items[s],this.direction=l?"up":"down"));if(!a&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[p])return this.currentContainer.containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash()),this.currentContainer.containerCache.over=1),void 0;a?this._rearrange(t,a,null,!0):this._rearrange(t,null,this.containers[p].element,!0),this._trigger("change",t,this._uiHash()),this.containers[p]._trigger("change",t,this._uiHash(this)),this.currentContainer=this.containers[p],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1}},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||e("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==this.document[0]&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===this.document[0].body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&e.ui.ie)&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var e=this.currentItem.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,"document"===n.containment?this.document.width():this.window.width()-this.helperProportions.width-this.margins.left,("document"===n.containment?this.document.width():this.window.height()||this.document[0].body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(t=e(n.containment)[0],i=e(n.containment).offset(),s="hidden"!==e(t).css("overflow"),this.containment=[i.left+(parseInt(e(t).css("borderLeftWidth"),10)||0)+(parseInt(e(t).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(e(t).css("borderTopWidth"),10)||0)+(parseInt(e(t).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(t.scrollWidth,t.offsetWidth):t.offsetWidth)-(parseInt(e(t).css("borderLeftWidth"),10)||0)-(parseInt(e(t).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(t.scrollHeight,t.offsetHeight):t.offsetHeight)-(parseInt(e(t).css("borderTopWidth"),10)||0)-(parseInt(e(t).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(t,i){i||(i=this.position);var s="absolute"===t?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,a=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():a?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():a?0:n.scrollLeft())*s}},_generatePosition:function(t){var i,s,n=this.options,a=t.pageX,o=t.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(t.pageX-this.offset.click.left<this.containment[0]&&(a=this.containment[0]+this.offset.click.left),t.pageY-this.offset.click.top<this.containment[1]&&(o=this.containment[1]+this.offset.click.top),t.pageX-this.offset.click.left>this.containment[2]&&(a=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1],o=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((a-this.originalPageX)/n.grid[0])*n.grid[0],a=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:o-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:a-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(e,t,i,s){i?i[0].appendChild(this.placeholder[0]):t.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?t.item[0]:t.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(e,t){function i(e,t,i){return function(s){i._trigger(e,s,t._uiHash(t))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!t&&n.push(function(e){this._trigger("receive",e,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||t||n.push(function(e){this._trigger("update",e,this._uiHash())}),this!==this.currentContainer&&(t||(n.push(function(e){this._trigger("remove",e,this._uiHash())}),n.push(function(e){return function(t){e._trigger("receive",t,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(e){return function(t){e._trigger("update",t,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)t||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,t||this._trigger("beforeStop",e,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!t){for(s=0;n.length>s;s++)n[s].call(this,e);this._trigger("stop",e,this._uiHash())}return this.fromOutside=!1,!this.cancelHelperRemoval},_trigger:function(){e.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(t){var i=t||this;return{helper:i.helper,placeholder:i.placeholder||e([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:t?t.element:null}}}),e.widget("ui.accordion",{version:"1.11.4",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},hideProps:{borderTopWidth:"hide",borderBottomWidth:"hide",paddingTop:"hide",paddingBottom:"hide",height:"hide"},showProps:{borderTopWidth:"show",borderBottomWidth:"show",paddingTop:"show",paddingBottom:"show",height:"show"},_create:function(){var t=this.options;this.prevShow=this.prevHide=e(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),t.collapsible||t.active!==!1&&null!=t.active||(t.active=0),this._processPanels(),0>t.active&&(t.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():e()}},_createIcons:function(){var t=this.options.icons;t&&(e("<span>").addClass("ui-accordion-header-icon ui-icon "+t.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(t.header).addClass(t.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var e;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").removeUniqueId(),this._destroyIcons(),e=this.headers.next().removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").css("display","").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeUniqueId(),"content"!==this.options.heightStyle&&e.css("height","")},_setOption:function(e,t){return"active"===e?(this._activate(t),void 0):("event"===e&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(t)),this._super(e,t),"collapsible"!==e||t||this.options.active!==!1||this._activate(0),"icons"===e&&(this._destroyIcons(),t&&this._createIcons()),"disabled"===e&&(this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!t)),void 0)},_keydown:function(t){if(!t.altKey&&!t.ctrlKey){var i=e.ui.keyCode,s=this.headers.length,n=this.headers.index(t.target),a=!1;switch(t.keyCode){case i.RIGHT:case i.DOWN:a=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:a=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(t);break;case i.HOME:a=this.headers[0];break;case i.END:a=this.headers[s-1]}a&&(e(t.target).attr("tabIndex",-1),e(a).attr("tabIndex",0),a.focus(),t.preventDefault())}},_panelKeyDown:function(t){t.keyCode===e.ui.keyCode.UP&&t.ctrlKey&&e(t.currentTarget).prev().focus()},refresh:function(){var t=this.options;this._processPanels(),t.active===!1&&t.collapsible===!0||!this.headers.length?(t.active=!1,this.active=e()):t.active===!1?this._activate(0):this.active.length&&!e.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(t.active=!1,this.active=e()):this._activate(Math.max(0,t.active-1)):t.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){var e=this.headers,t=this.panels;this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-state-default ui-corner-all"),this.panels=this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide(),t&&(this._off(e.not(this.headers)),this._off(t.not(this.panels)))
+},_refresh:function(){var t,i=this.options,s=i.heightStyle,n=this.element.parent();this.active=this._findActive(i.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(){var t=e(this),i=t.uniqueId().attr("id"),s=t.next(),n=s.uniqueId().attr("id");t.attr("aria-controls",n),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(i.event),"fill"===s?(t=n.height(),this.element.siblings(":visible").each(function(){var i=e(this),s=i.css("position");"absolute"!==s&&"fixed"!==s&&(t-=i.outerHeight(!0))}),this.headers.each(function(){t-=e(this).outerHeight(!0)}),this.headers.next().each(function(){e(this).height(Math.max(0,t-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):"auto"===s&&(t=0,this.headers.next().each(function(){t=Math.max(t,e(this).css("height","").height())}).height(t))},_activate:function(t){var i=this._findActive(t)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:e.noop}))},_findActive:function(t){return"number"==typeof t?this.headers.eq(t):e()},_setupEvents:function(t){var i={keydown:"_keydown"};t&&e.each(t.split(" "),function(e,t){i[t]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(t){var i=this.options,s=this.active,n=e(t.currentTarget),a=n[0]===s[0],o=a&&i.collapsible,r=o?e():n.next(),h=s.next(),l={oldHeader:s,oldPanel:h,newHeader:o?e():n,newPanel:r};t.preventDefault(),a&&!i.collapsible||this._trigger("beforeActivate",t,l)===!1||(i.active=o?!1:this.headers.index(n),this.active=a?e():n,this._toggle(l),s.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),a||(n.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&n.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),n.next().addClass("ui-accordion-content-active")))},_toggle:function(t){var i=t.newPanel,s=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,t):(s.hide(),i.show(),this._toggleComplete(t)),s.attr({"aria-hidden":"true"}),s.prev().attr({"aria-selected":"false","aria-expanded":"false"}),i.length&&s.length?s.prev().attr({tabIndex:-1,"aria-expanded":"false"}):i.length&&this.headers.filter(function(){return 0===parseInt(e(this).attr("tabIndex"),10)}).attr("tabIndex",-1),i.attr("aria-hidden","false").prev().attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_animate:function(e,t,i){var s,n,a,o=this,r=0,h=e.css("box-sizing"),l=e.length&&(!t.length||e.index()<t.index()),u=this.options.animate||{},d=l&&u.down||u,c=function(){o._toggleComplete(i)};return"number"==typeof d&&(a=d),"string"==typeof d&&(n=d),n=n||d.easing||u.easing,a=a||d.duration||u.duration,t.length?e.length?(s=e.show().outerHeight(),t.animate(this.hideProps,{duration:a,easing:n,step:function(e,t){t.now=Math.round(e)}}),e.hide().animate(this.showProps,{duration:a,easing:n,complete:c,step:function(e,i){i.now=Math.round(e),"height"!==i.prop?"content-box"===h&&(r+=i.now):"content"!==o.options.heightStyle&&(i.now=Math.round(s-t.outerHeight()-r),r=0)}}),void 0):t.animate(this.hideProps,a,n,c):e.animate(this.showProps,a,n,c)},_toggleComplete:function(e){var t=e.oldPanel;t.removeClass("ui-accordion-content-active").prev().removeClass("ui-corner-top").addClass("ui-corner-all"),t.length&&(t.parent()[0].className=t.parent()[0].className),this._trigger("activate",null,e)}}),e.widget("ui.menu",{version:"1.11.4",defaultElement:"<ul>",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},items:"> *",menus:"ul",position:{my:"left-1 top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item":function(e){e.preventDefault()},"click .ui-menu-item":function(t){var i=e(t.target);!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.select(t),t.isPropagationStopped()||(this.mouseHandled=!0),i.has(".ui-menu").length?this.expand(t):!this.element.is(":focus")&&e(this.document[0].activeElement).closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(t){if(!this.previousFilter){var i=e(t.currentTarget);i.siblings(".ui-state-active").removeClass("ui-state-active"),this.focus(t,i)}},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(e,t){var i=this.active||this.element.find(this.options.items).eq(0);t||this.focus(e,i)},blur:function(t){this._delay(function(){e.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(e){this._closeOnDocumentClick(e)&&this.collapseAll(e),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-menu-icons ui-front").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").removeUniqueId().removeClass("ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var t=e(this);t.data("ui-menu-submenu-carat")&&t.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(t){var i,s,n,a,o=!0;switch(t.keyCode){case e.ui.keyCode.PAGE_UP:this.previousPage(t);break;case e.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case e.ui.keyCode.HOME:this._move("first","first",t);break;case e.ui.keyCode.END:this._move("last","last",t);break;case e.ui.keyCode.UP:this.previous(t);break;case e.ui.keyCode.DOWN:this.next(t);break;case e.ui.keyCode.LEFT:this.collapse(t);break;case e.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case e.ui.keyCode.ENTER:case e.ui.keyCode.SPACE:this._activate(t);break;case e.ui.keyCode.ESCAPE:this.collapse(t);break;default:o=!1,s=this.previousFilter||"",n=String.fromCharCode(t.keyCode),a=!1,clearTimeout(this.filterTimer),n===s?a=!0:n=s+n,i=this._filterMenuItems(n),i=a&&-1!==i.index(this.active.next())?this.active.nextAll(".ui-menu-item"):i,i.length||(n=String.fromCharCode(t.keyCode),i=this._filterMenuItems(n)),i.length?(this.focus(t,i),this.previousFilter=n,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}o&&t.preventDefault()},_activate:function(e){this.active.is(".ui-state-disabled")||(this.active.is("[aria-haspopup='true']")?this.expand(e):this.select(e))},refresh:function(){var t,i,s=this,n=this.options.icons.submenu,a=this.element.find(this.options.menus);this.element.toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length),a.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-front").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=e(this),i=t.parent(),s=e("<span>").addClass("ui-menu-icon ui-icon "+n).data("ui-menu-submenu-carat",!0);i.attr("aria-haspopup","true").prepend(s),t.attr("aria-labelledby",i.attr("id"))}),t=a.add(this.element),i=t.find(this.options.items),i.not(".ui-menu-item").each(function(){var t=e(this);s._isDivider(t)&&t.addClass("ui-widget-content ui-menu-divider")}),i.not(".ui-menu-item, .ui-menu-divider").addClass("ui-menu-item").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),i.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!e.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(e,t){"icons"===e&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(t.submenu),"disabled"===e&&this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this._super(e,t)},focus:function(e,t){var i,s;this.blur(e,e&&"focus"===e.type),this._scrollIntoView(t),this.active=t.first(),s=this.active.addClass("ui-state-focus").removeClass("ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),this.active.parent().closest(".ui-menu-item").addClass("ui-state-active"),e&&"keydown"===e.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=t.children(".ui-menu"),i.length&&e&&/^mouse/.test(e.type)&&this._startOpening(i),this.activeMenu=t.parent(),this._trigger("focus",e,{item:t})},_scrollIntoView:function(t){var i,s,n,a,o,r;this._hasScroll()&&(i=parseFloat(e.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(e.css(this.activeMenu[0],"paddingTop"))||0,n=t.offset().top-this.activeMenu.offset().top-i-s,a=this.activeMenu.scrollTop(),o=this.activeMenu.height(),r=t.outerHeight(),0>n?this.activeMenu.scrollTop(a+n):n+r>o&&this.activeMenu.scrollTop(a+n-o+r))},blur:function(e,t){t||clearTimeout(this.timer),this.active&&(this.active.removeClass("ui-state-focus"),this.active=null,this._trigger("blur",e,{item:this.active}))},_startOpening:function(e){clearTimeout(this.timer),"true"===e.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(e)},this.delay))},_open:function(t){var i=e.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(t.parents(".ui-menu")).hide().attr("aria-hidden","true"),t.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(t,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:e(t&&t.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(t),this.activeMenu=s},this.delay)},_close:function(e){e||(e=this.active?this.active.parent():this.element),e.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find(".ui-state-active").not(".ui-state-focus").removeClass("ui-state-active")},_closeOnDocumentClick:function(t){return!e(t.target).closest(".ui-menu").length},_isDivider:function(e){return!/[^\-\u2014\u2013\s]/.test(e.text())},collapse:function(e){var t=this.active&&this.active.parent().closest(".ui-menu-item",this.element);t&&t.length&&(this._close(),this.focus(e,t))},expand:function(e){var t=this.active&&this.active.children(".ui-menu ").find(this.options.items).first();t&&t.length&&(this._open(t.parent()),this._delay(function(){this.focus(e,t)}))},next:function(e){this._move("next","first",e)},previous:function(e){this._move("prev","last",e)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(e,t,i){var s;this.active&&(s="first"===e||"last"===e?this.active["first"===e?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[e+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.find(this.options.items)[t]()),this.focus(i,s)},nextPage:function(t){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=e(this),0>i.offset().top-s-n}),this.focus(t,i)):this.focus(t,this.activeMenu.find(this.options.items)[this.active?"last":"first"]())),void 0):(this.next(t),void 0)},previousPage:function(t){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=e(this),i.offset().top-s+n>0}),this.focus(t,i)):this.focus(t,this.activeMenu.find(this.options.items).first())),void 0):(this.next(t),void 0)},_hasScroll:function(){return this.element.outerHeight()<this.element.prop("scrollHeight")},select:function(t){this.active=this.active||e(t.target).closest(".ui-menu-item");var i={item:this.active};this.active.has(".ui-menu").length||this.collapseAll(t,!0),this._trigger("select",t,i)},_filterMenuItems:function(t){var i=t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&"),s=RegExp("^"+i,"i");return this.activeMenu.find(this.options.items).filter(".ui-menu-item").filter(function(){return s.test(e.trim(e(this).text()))})}}),e.widget("ui.autocomplete",{version:"1.11.4",defaultElement:"<input>",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var t,i,s,n=this.element[0].nodeName.toLowerCase(),a="textarea"===n,o="input"===n;this.isMultiLine=a?!0:o?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[a||o?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return t=!0,s=!0,i=!0,void 0;t=!1,s=!1,i=!1;var a=e.ui.keyCode;switch(n.keyCode){case a.PAGE_UP:t=!0,this._move("previousPage",n);break;case a.PAGE_DOWN:t=!0,this._move("nextPage",n);break;case a.UP:t=!0,this._keyEvent("previous",n);break;case a.DOWN:t=!0,this._keyEvent("next",n);break;case a.ENTER:this.menu.active&&(t=!0,n.preventDefault(),this.menu.select(n));break;case a.TAB:this.menu.active&&this.menu.select(n);break;case a.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(t)return t=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),void 0;if(!i){var n=e.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(e){return s?(s=!1,e.preventDefault(),void 0):(this._searchTimeout(e),void 0)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(e){return this.cancelBlur?(delete this.cancelBlur,void 0):(clearTimeout(this.searching),this.close(e),this._change(e),void 0)}}),this._initSource(),this.menu=e("<ul>").addClass("ui-autocomplete ui-front").appendTo(this._appendTo()).menu({role:null}).hide().menu("instance"),this._on(this.menu.element,{mousedown:function(t){t.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur});var i=this.menu.element[0];e(t.target).closest(".ui-menu-item").length||this._delay(function(){var t=this;this.document.one("mousedown",function(s){s.target===t.element[0]||s.target===i||e.contains(i,s.target)||t.close()})})},menufocus:function(t,i){var s,n;return this.isNewMenu&&(this.isNewMenu=!1,t.originalEvent&&/^mouse/.test(t.originalEvent.type))?(this.menu.blur(),this.document.one("mousemove",function(){e(t.target).trigger(t.originalEvent)}),void 0):(n=i.item.data("ui-autocomplete-item"),!1!==this._trigger("focus",t,{item:n})&&t.originalEvent&&/^key/.test(t.originalEvent.type)&&this._value(n.value),s=i.item.attr("aria-label")||n.value,s&&e.trim(s).length&&(this.liveRegion.children().hide(),e("<div>").text(s).appendTo(this.liveRegion)),void 0)},menuselect:function(e,t){var i=t.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==this.document[0].activeElement&&(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",e,{item:i})&&this._value(i.value),this.term=this._value(),this.close(e),this.selectedItem=i}}),this.liveRegion=e("<span>",{role:"status","aria-live":"assertive","aria-relevant":"additions"}).addClass("ui-helper-hidden-accessible").appendTo(this.document[0].body),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(e,t){this._super(e,t),"source"===e&&this._initSource(),"appendTo"===e&&this.menu.element.appendTo(this._appendTo()),"disabled"===e&&t&&this.xhr&&this.xhr.abort()},_appendTo:function(){var t=this.options.appendTo;return t&&(t=t.jquery||t.nodeType?e(t):this.document.find(t).eq(0)),t&&t[0]||(t=this.element.closest(".ui-front")),t.length||(t=this.document[0].body),t},_initSource:function(){var t,i,s=this;e.isArray(this.options.source)?(t=this.options.source,this.source=function(i,s){s(e.ui.autocomplete.filter(t,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(t,n){s.xhr&&s.xhr.abort(),s.xhr=e.ajax({url:i,data:t,dataType:"json",success:function(e){n(e)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(e){clearTimeout(this.searching),this.searching=this._delay(function(){var t=this.term===this._value(),i=this.menu.element.is(":visible"),s=e.altKey||e.ctrlKey||e.metaKey||e.shiftKey;(!t||t&&!i&&!s)&&(this.selectedItem=null,this.search(null,e))},this.options.delay)},search:function(e,t){return e=null!=e?e:this._value(),this.term=this._value(),e.length<this.options.minLength?this.close(t):this._trigger("search",t)!==!1?this._search(e):void 0},_search:function(e){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.cancelSearch=!1,this.source({term:e},this._response())},_response:function(){var t=++this.requestIndex;return e.proxy(function(e){t===this.requestIndex&&this.__response(e),this.pending--,this.pending||this.element.removeClass("ui-autocomplete-loading")},this)},__response:function(e){e&&(e=this._normalize(e)),this._trigger("response",null,{content:e}),!this.options.disabled&&e&&e.length&&!this.cancelSearch?(this._suggest(e),this._trigger("open")):this._close()},close:function(e){this.cancelSearch=!0,this._close(e)},_close:function(e){this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.blur(),this.isNewMenu=!0,this._trigger("close",e))},_change:function(e){this.previous!==this._value()&&this._trigger("change",e,{item:this.selectedItem})},_normalize:function(t){return t.length&&t[0].label&&t[0].value?t:e.map(t,function(t){return"string"==typeof t?{label:t,value:t}:e.extend({},t,{label:t.label||t.value,value:t.value||t.label})})},_suggest:function(t){var i=this.menu.element.empty();this._renderMenu(i,t),this.isNewMenu=!0,this.menu.refresh(),i.show(),this._resizeMenu(),i.position(e.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next()},_resizeMenu:function(){var e=this.menu.element;e.outerWidth(Math.max(e.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(t,i){var s=this;e.each(i,function(e,i){s._renderItemData(t,i)})},_renderItemData:function(e,t){return this._renderItem(e,t).data("ui-autocomplete-item",t)},_renderItem:function(t,i){return e("<li>").text(i.label).appendTo(t)},_move:function(e,t){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(e)||this.menu.isLastItem()&&/^next/.test(e)?(this.isMultiLine||this._value(this.term),this.menu.blur(),void 0):(this.menu[e](t),void 0):(this.search(null,t),void 0)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(e,t){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(e,t),t.preventDefault())}}),e.extend(e.ui.autocomplete,{escapeRegex:function(e){return e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(t,i){var s=RegExp(e.ui.autocomplete.escapeRegex(i),"i");return e.grep(t,function(e){return s.test(e.label||e.value||e)})}}),e.widget("ui.autocomplete",e.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(e){return e+(e>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(t){var i;this._superApply(arguments),this.options.disabled||this.cancelSearch||(i=t&&t.length?this.options.messages.results(t.length):this.options.messages.noResults,this.liveRegion.children().hide(),e("<div>").text(i).appendTo(this.liveRegion))}}),e.ui.autocomplete;var c,p="ui-button ui-widget ui-state-default ui-corner-all",f="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",m=function(){var t=e(this);setTimeout(function(){t.find(":ui-button").button("refresh")},1)},g=function(t){var i=t.name,s=t.form,n=e([]);return i&&(i=i.replace(/'/g,"\\'"),n=s?e(s).find("[name='"+i+"'][type=radio]"):e("[name='"+i+"'][type=radio]",t.ownerDocument).filter(function(){return!this.form})),n};e.widget("ui.button",{version:"1.11.4",defaultElement:"<button>",options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset"+this.eventNamespace).bind("reset"+this.eventNamespace,m),"boolean"!=typeof this.options.disabled?this.options.disabled=!!this.element.prop("disabled"):this.element.prop("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var t=this,i=this.options,s="checkbox"===this.type||"radio"===this.type,n=s?"":"ui-state-active";null===i.label&&(i.label="input"===this.type?this.buttonElement.val():this.buttonElement.html()),this._hoverable(this.buttonElement),this.buttonElement.addClass(p).attr("role","button").bind("mouseenter"+this.eventNamespace,function(){i.disabled||this===c&&e(this).addClass("ui-state-active")}).bind("mouseleave"+this.eventNamespace,function(){i.disabled||e(this).removeClass(n)}).bind("click"+this.eventNamespace,function(e){i.disabled&&(e.preventDefault(),e.stopImmediatePropagation())}),this._on({focus:function(){this.buttonElement.addClass("ui-state-focus")},blur:function(){this.buttonElement.removeClass("ui-state-focus")}}),s&&this.element.bind("change"+this.eventNamespace,function(){t.refresh()}),"checkbox"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){return i.disabled?!1:void 0}):"radio"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){if(i.disabled)return!1;e(this).addClass("ui-state-active"),t.buttonElement.attr("aria-pressed","true");var s=t.element[0];g(s).not(s).map(function(){return e(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown"+this.eventNamespace,function(){return i.disabled?!1:(e(this).addClass("ui-state-active"),c=this,t.document.one("mouseup",function(){c=null}),void 0)}).bind("mouseup"+this.eventNamespace,function(){return i.disabled?!1:(e(this).removeClass("ui-state-active"),void 0)}).bind("keydown"+this.eventNamespace,function(t){return i.disabled?!1:((t.keyCode===e.ui.keyCode.SPACE||t.keyCode===e.ui.keyCode.ENTER)&&e(this).addClass("ui-state-active"),void 0)}).bind("keyup"+this.eventNamespace+" blur"+this.eventNamespace,function(){e(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(t){t.keyCode===e.ui.keyCode.SPACE&&e(this).click()})),this._setOption("disabled",i.disabled),this._resetButton()},_determineButtonType:function(){var e,t,i;this.type=this.element.is("[type=checkbox]")?"checkbox":this.element.is("[type=radio]")?"radio":this.element.is("input")?"input":"button","checkbox"===this.type||"radio"===this.type?(e=this.element.parents().last(),t="label[for='"+this.element.attr("id")+"']",this.buttonElement=e.find(t),this.buttonElement.length||(e=e.length?e.siblings():this.element.siblings(),this.buttonElement=e.filter(t),this.buttonElement.length||(this.buttonElement=e.find(t))),this.element.addClass("ui-helper-hidden-accessible"),i=this.element.is(":checked"),i&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.prop("aria-pressed",i)):this.buttonElement=this.element},widget:function(){return this.buttonElement},_destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(p+" ui-state-active "+f).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title")},_setOption:function(e,t){return this._super(e,t),"disabled"===e?(this.widget().toggleClass("ui-state-disabled",!!t),this.element.prop("disabled",!!t),t&&("checkbox"===this.type||"radio"===this.type?this.buttonElement.removeClass("ui-state-focus"):this.buttonElement.removeClass("ui-state-focus ui-state-active")),void 0):(this._resetButton(),void 0)},refresh:function(){var t=this.element.is("input, button")?this.element.is(":disabled"):this.element.hasClass("ui-button-disabled");t!==this.options.disabled&&this._setOption("disabled",t),"radio"===this.type?g(this.element[0]).each(function(){e(this).is(":checked")?e(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):e(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):"checkbox"===this.type&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if("input"===this.type)return this.options.label&&this.element.val(this.options.label),void 0;var t=this.buttonElement.removeClass(f),i=e("<span></span>",this.document[0]).addClass("ui-button-text").html(this.options.label).appendTo(t.empty()).text(),s=this.options.icons,n=s.primary&&s.secondary,a=[];s.primary||s.secondary?(this.options.text&&a.push("ui-button-text-icon"+(n?"s":s.primary?"-primary":"-secondary")),s.primary&&t.prepend("<span class='ui-button-icon-primary ui-icon "+s.primary+"'></span>"),s.secondary&&t.append("<span class='ui-button-icon-secondary ui-icon "+s.secondary+"'></span>"),this.options.text||(a.push(n?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||t.attr("title",e.trim(i)))):a.push("ui-button-text-only"),t.addClass(a.join(" "))}}),e.widget("ui.buttonset",{version:"1.11.4",options:{items:"button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(e,t){"disabled"===e&&this.buttons.button("option",e,t),this._super(e,t)},refresh:function(){var t="rtl"===this.element.css("direction"),i=this.element.find(this.options.items),s=i.filter(":ui-button");i.not(":ui-button").button(),s.button("refresh"),this.buttons=i.map(function(){return e(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(t?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(t?"ui-corner-left":"ui-corner-right").end().end()},_destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return e(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy")}}),e.ui.button,e.extend(e.ui,{datepicker:{version:"1.11.4"}});var v;e.extend(n.prototype,{markerClassName:"hasDatepicker",maxRows:4,_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(e){return r(this._defaults,e||{}),this},_attachDatepicker:function(t,i){var s,n,a;s=t.nodeName.toLowerCase(),n="div"===s||"span"===s,t.id||(this.uuid+=1,t.id="dp"+this.uuid),a=this._newInst(e(t),n),a.settings=e.extend({},i||{}),"input"===s?this._connectDatepicker(t,a):n&&this._inlineDatepicker(t,a)},_newInst:function(t,i){var s=t[0].id.replace(/([^A-Za-z0-9_\-])/g,"\\\\$1");return{id:s,input:t,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:i,dpDiv:i?a(e("<div class='"+this._inlineClass+" ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")):this.dpDiv}},_connectDatepicker:function(t,i){var s=e(t);i.append=e([]),i.trigger=e([]),s.hasClass(this.markerClassName)||(this._attachments(s,i),s.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp),this._autoSize(i),e.data(t,"datepicker",i),i.settings.disabled&&this._disableDatepicker(t))},_attachments:function(t,i){var s,n,a,o=this._get(i,"appendText"),r=this._get(i,"isRTL");i.append&&i.append.remove(),o&&(i.append=e("<span class='"+this._appendClass+"'>"+o+"</span>"),t[r?"before":"after"](i.append)),t.unbind("focus",this._showDatepicker),i.trigger&&i.trigger.remove(),s=this._get(i,"showOn"),("focus"===s||"both"===s)&&t.focus(this._showDatepicker),("button"===s||"both"===s)&&(n=this._get(i,"buttonText"),a=this._get(i,"buttonImage"),i.trigger=e(this._get(i,"buttonImageOnly")?e("<img/>").addClass(this._triggerClass).attr({src:a,alt:n,title:n}):e("<button type='button'></button>").addClass(this._triggerClass).html(a?e("<img/>").attr({src:a,alt:n,title:n}):n)),t[r?"before":"after"](i.trigger),i.trigger.click(function(){return e.datepicker._datepickerShowing&&e.datepicker._lastInput===t[0]?e.datepicker._hideDatepicker():e.datepicker._datepickerShowing&&e.datepicker._lastInput!==t[0]?(e.datepicker._hideDatepicker(),e.datepicker._showDatepicker(t[0])):e.datepicker._showDatepicker(t[0]),!1}))},_autoSize:function(e){if(this._get(e,"autoSize")&&!e.inline){var t,i,s,n,a=new Date(2009,11,20),o=this._get(e,"dateFormat");o.match(/[DM]/)&&(t=function(e){for(i=0,s=0,n=0;e.length>n;n++)e[n].length>i&&(i=e[n].length,s=n);return s},a.setMonth(t(this._get(e,o.match(/MM/)?"monthNames":"monthNamesShort"))),a.setDate(t(this._get(e,o.match(/DD/)?"dayNames":"dayNamesShort"))+20-a.getDay())),e.input.attr("size",this._formatDate(e,a).length)}},_inlineDatepicker:function(t,i){var s=e(t);s.hasClass(this.markerClassName)||(s.addClass(this.markerClassName).append(i.dpDiv),e.data(t,"datepicker",i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(t),i.dpDiv.css("display","block"))},_dialogDatepicker:function(t,i,s,n,a){var o,h,l,u,d,c=this._dialogInst;return c||(this.uuid+=1,o="dp"+this.uuid,this._dialogInput=e("<input type='text' id='"+o+"' style='position: absolute; top: -100px; width: 0px;'/>"),this._dialogInput.keydown(this._doKeyDown),e("body").append(this._dialogInput),c=this._dialogInst=this._newInst(this._dialogInput,!1),c.settings={},e.data(this._dialogInput[0],"datepicker",c)),r(c.settings,n||{}),i=i&&i.constructor===Date?this._formatDate(c,i):i,this._dialogInput.val(i),this._pos=a?a.length?a:[a.pageX,a.pageY]:null,this._pos||(h=document.documentElement.clientWidth,l=document.documentElement.clientHeight,u=document.documentElement.scrollLeft||document.body.scrollLeft,d=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[h/2-100+u,l/2-150+d]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),c.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),e.blockUI&&e.blockUI(this.dpDiv),e.data(this._dialogInput[0],"datepicker",c),this
+},_destroyDatepicker:function(t){var i,s=e(t),n=e.data(t,"datepicker");s.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),e.removeData(t,"datepicker"),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty(),v===n&&(v=null))},_enableDatepicker:function(t){var i,s,n=e(t),a=e.data(t,"datepicker");n.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),"input"===i?(t.disabled=!1,a.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=e.map(this._disabledInputs,function(e){return e===t?null:e}))},_disableDatepicker:function(t){var i,s,n=e(t),a=e.data(t,"datepicker");n.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),"input"===i?(t.disabled=!0,a.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=e.map(this._disabledInputs,function(e){return e===t?null:e}),this._disabledInputs[this._disabledInputs.length]=t)},_isDisabledDatepicker:function(e){if(!e)return!1;for(var t=0;this._disabledInputs.length>t;t++)if(this._disabledInputs[t]===e)return!0;return!1},_getInst:function(t){try{return e.data(t,"datepicker")}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(t,i,s){var n,a,o,h,l=this._getInst(t);return 2===arguments.length&&"string"==typeof i?"defaults"===i?e.extend({},e.datepicker._defaults):l?"all"===i?e.extend({},l.settings):this._get(l,i):null:(n=i||{},"string"==typeof i&&(n={},n[i]=s),l&&(this._curInst===l&&this._hideDatepicker(),a=this._getDateDatepicker(t,!0),o=this._getMinMaxDate(l,"min"),h=this._getMinMaxDate(l,"max"),r(l.settings,n),null!==o&&void 0!==n.dateFormat&&void 0===n.minDate&&(l.settings.minDate=this._formatDate(l,o)),null!==h&&void 0!==n.dateFormat&&void 0===n.maxDate&&(l.settings.maxDate=this._formatDate(l,h)),"disabled"in n&&(n.disabled?this._disableDatepicker(t):this._enableDatepicker(t)),this._attachments(e(t),l),this._autoSize(l),this._setDate(l,a),this._updateAlternate(l),this._updateDatepicker(l)),void 0)},_changeDatepicker:function(e,t,i){this._optionDatepicker(e,t,i)},_refreshDatepicker:function(e){var t=this._getInst(e);t&&this._updateDatepicker(t)},_setDateDatepicker:function(e,t){var i=this._getInst(e);i&&(this._setDate(i,t),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(e,t){var i=this._getInst(e);return i&&!i.inline&&this._setDateFromField(i,t),i?this._getDate(i):null},_doKeyDown:function(t){var i,s,n,a=e.datepicker._getInst(t.target),o=!0,r=a.dpDiv.is(".ui-datepicker-rtl");if(a._keyEvent=!0,e.datepicker._datepickerShowing)switch(t.keyCode){case 9:e.datepicker._hideDatepicker(),o=!1;break;case 13:return n=e("td."+e.datepicker._dayOverClass+":not(."+e.datepicker._currentClass+")",a.dpDiv),n[0]&&e.datepicker._selectDay(t.target,a.selectedMonth,a.selectedYear,n[0]),i=e.datepicker._get(a,"onSelect"),i?(s=e.datepicker._formatDate(a),i.apply(a.input?a.input[0]:null,[s,a])):e.datepicker._hideDatepicker(),!1;case 27:e.datepicker._hideDatepicker();break;case 33:e.datepicker._adjustDate(t.target,t.ctrlKey?-e.datepicker._get(a,"stepBigMonths"):-e.datepicker._get(a,"stepMonths"),"M");break;case 34:e.datepicker._adjustDate(t.target,t.ctrlKey?+e.datepicker._get(a,"stepBigMonths"):+e.datepicker._get(a,"stepMonths"),"M");break;case 35:(t.ctrlKey||t.metaKey)&&e.datepicker._clearDate(t.target),o=t.ctrlKey||t.metaKey;break;case 36:(t.ctrlKey||t.metaKey)&&e.datepicker._gotoToday(t.target),o=t.ctrlKey||t.metaKey;break;case 37:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,r?1:-1,"D"),o=t.ctrlKey||t.metaKey,t.originalEvent.altKey&&e.datepicker._adjustDate(t.target,t.ctrlKey?-e.datepicker._get(a,"stepBigMonths"):-e.datepicker._get(a,"stepMonths"),"M");break;case 38:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,-7,"D"),o=t.ctrlKey||t.metaKey;break;case 39:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,r?-1:1,"D"),o=t.ctrlKey||t.metaKey,t.originalEvent.altKey&&e.datepicker._adjustDate(t.target,t.ctrlKey?+e.datepicker._get(a,"stepBigMonths"):+e.datepicker._get(a,"stepMonths"),"M");break;case 40:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,7,"D"),o=t.ctrlKey||t.metaKey;break;default:o=!1}else 36===t.keyCode&&t.ctrlKey?e.datepicker._showDatepicker(this):o=!1;o&&(t.preventDefault(),t.stopPropagation())},_doKeyPress:function(t){var i,s,n=e.datepicker._getInst(t.target);return e.datepicker._get(n,"constrainInput")?(i=e.datepicker._possibleChars(e.datepicker._get(n,"dateFormat")),s=String.fromCharCode(null==t.charCode?t.keyCode:t.charCode),t.ctrlKey||t.metaKey||" ">s||!i||i.indexOf(s)>-1):void 0},_doKeyUp:function(t){var i,s=e.datepicker._getInst(t.target);if(s.input.val()!==s.lastVal)try{i=e.datepicker.parseDate(e.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,e.datepicker._getFormatConfig(s)),i&&(e.datepicker._setDateFromField(s),e.datepicker._updateAlternate(s),e.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(t){if(t=t.target||t,"input"!==t.nodeName.toLowerCase()&&(t=e("input",t.parentNode)[0]),!e.datepicker._isDisabledDatepicker(t)&&e.datepicker._lastInput!==t){var i,n,a,o,h,l,u;i=e.datepicker._getInst(t),e.datepicker._curInst&&e.datepicker._curInst!==i&&(e.datepicker._curInst.dpDiv.stop(!0,!0),i&&e.datepicker._datepickerShowing&&e.datepicker._hideDatepicker(e.datepicker._curInst.input[0])),n=e.datepicker._get(i,"beforeShow"),a=n?n.apply(t,[t,i]):{},a!==!1&&(r(i.settings,a),i.lastVal=null,e.datepicker._lastInput=t,e.datepicker._setDateFromField(i),e.datepicker._inDialog&&(t.value=""),e.datepicker._pos||(e.datepicker._pos=e.datepicker._findPos(t),e.datepicker._pos[1]+=t.offsetHeight),o=!1,e(t).parents().each(function(){return o|="fixed"===e(this).css("position"),!o}),h={left:e.datepicker._pos[0],top:e.datepicker._pos[1]},e.datepicker._pos=null,i.dpDiv.empty(),i.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),e.datepicker._updateDatepicker(i),h=e.datepicker._checkOffset(i,h,o),i.dpDiv.css({position:e.datepicker._inDialog&&e.blockUI?"static":o?"fixed":"absolute",display:"none",left:h.left+"px",top:h.top+"px"}),i.inline||(l=e.datepicker._get(i,"showAnim"),u=e.datepicker._get(i,"duration"),i.dpDiv.css("z-index",s(e(t))+1),e.datepicker._datepickerShowing=!0,e.effects&&e.effects.effect[l]?i.dpDiv.show(l,e.datepicker._get(i,"showOptions"),u):i.dpDiv[l||"show"](l?u:null),e.datepicker._shouldFocusInput(i)&&i.input.focus(),e.datepicker._curInst=i))}},_updateDatepicker:function(t){this.maxRows=4,v=t,t.dpDiv.empty().append(this._generateHTML(t)),this._attachHandlers(t);var i,s=this._getNumberOfMonths(t),n=s[1],a=17,r=t.dpDiv.find("."+this._dayOverClass+" a");r.length>0&&o.apply(r.get(0)),t.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&t.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",a*n+"em"),t.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),t.dpDiv[(this._get(t,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),t===e.datepicker._curInst&&e.datepicker._datepickerShowing&&e.datepicker._shouldFocusInput(t)&&t.input.focus(),t.yearshtml&&(i=t.yearshtml,setTimeout(function(){i===t.yearshtml&&t.yearshtml&&t.dpDiv.find("select.ui-datepicker-year:first").replaceWith(t.yearshtml),i=t.yearshtml=null},0))},_shouldFocusInput:function(e){return e.input&&e.input.is(":visible")&&!e.input.is(":disabled")&&!e.input.is(":focus")},_checkOffset:function(t,i,s){var n=t.dpDiv.outerWidth(),a=t.dpDiv.outerHeight(),o=t.input?t.input.outerWidth():0,r=t.input?t.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:e(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:e(document).scrollTop());return i.left-=this._get(t,"isRTL")?n-o:0,i.left-=s&&i.left===t.input.offset().left?e(document).scrollLeft():0,i.top-=s&&i.top===t.input.offset().top+r?e(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+a>l&&l>a?Math.abs(a+r):0),i},_findPos:function(t){for(var i,s=this._getInst(t),n=this._get(s,"isRTL");t&&("hidden"===t.type||1!==t.nodeType||e.expr.filters.hidden(t));)t=t[n?"previousSibling":"nextSibling"];return i=e(t).offset(),[i.left,i.top]},_hideDatepicker:function(t){var i,s,n,a,o=this._curInst;!o||t&&o!==e.data(t,"datepicker")||this._datepickerShowing&&(i=this._get(o,"showAnim"),s=this._get(o,"duration"),n=function(){e.datepicker._tidyDialog(o)},e.effects&&(e.effects.effect[i]||e.effects[i])?o.dpDiv.hide(i,e.datepicker._get(o,"showOptions"),s,n):o.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,a=this._get(o,"onClose"),a&&a.apply(o.input?o.input[0]:null,[o.input?o.input.val():"",o]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),e.blockUI&&(e.unblockUI(),e("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(e){e.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(t){if(e.datepicker._curInst){var i=e(t.target),s=e.datepicker._getInst(i[0]);(i[0].id!==e.datepicker._mainDivId&&0===i.parents("#"+e.datepicker._mainDivId).length&&!i.hasClass(e.datepicker.markerClassName)&&!i.closest("."+e.datepicker._triggerClass).length&&e.datepicker._datepickerShowing&&(!e.datepicker._inDialog||!e.blockUI)||i.hasClass(e.datepicker.markerClassName)&&e.datepicker._curInst!==s)&&e.datepicker._hideDatepicker()}},_adjustDate:function(t,i,s){var n=e(t),a=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(a,i+("M"===s?this._get(a,"showCurrentAtPos"):0),s),this._updateDatepicker(a))},_gotoToday:function(t){var i,s=e(t),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(t,i,s){var n=e(t),a=this._getInst(n[0]);a["selected"+("M"===s?"Month":"Year")]=a["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(a),this._adjustDate(n)},_selectDay:function(t,i,s,n){var a,o=e(t);e(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(o[0])||(a=this._getInst(o[0]),a.selectedDay=a.currentDay=e("a",n).html(),a.selectedMonth=a.currentMonth=i,a.selectedYear=a.currentYear=s,this._selectDate(t,this._formatDate(a,a.currentDay,a.currentMonth,a.currentYear)))},_clearDate:function(t){var i=e(t);this._selectDate(i,"")},_selectDate:function(t,i){var s,n=e(t),a=this._getInst(n[0]);i=null!=i?i:this._formatDate(a),a.input&&a.input.val(i),this._updateAlternate(a),s=this._get(a,"onSelect"),s?s.apply(a.input?a.input[0]:null,[i,a]):a.input&&a.input.trigger("change"),a.inline?this._updateDatepicker(a):(this._hideDatepicker(),this._lastInput=a.input[0],"object"!=typeof a.input[0]&&a.input.focus(),this._lastInput=null)},_updateAlternate:function(t){var i,s,n,a=this._get(t,"altField");a&&(i=this._get(t,"altFormat")||this._get(t,"dateFormat"),s=this._getDate(t),n=this.formatDate(i,s,this._getFormatConfig(t)),e(a).each(function(){e(this).val(n)}))},noWeekends:function(e){var t=e.getDay();return[t>0&&6>t,""]},iso8601Week:function(e){var t,i=new Date(e.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),t=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((t-i)/864e5)/7)+1},parseDate:function(t,i,s){if(null==t||null==i)throw"Invalid arguments";if(i="object"==typeof i?""+i:i+"",""===i)return null;var n,a,o,r,h=0,l=(s?s.shortYearCutoff:null)||this._defaults.shortYearCutoff,u="string"!=typeof l?l:(new Date).getFullYear()%100+parseInt(l,10),d=(s?s.dayNamesShort:null)||this._defaults.dayNamesShort,c=(s?s.dayNames:null)||this._defaults.dayNames,p=(s?s.monthNamesShort:null)||this._defaults.monthNamesShort,f=(s?s.monthNames:null)||this._defaults.monthNames,m=-1,g=-1,v=-1,y=-1,b=!1,_=function(e){var i=t.length>n+1&&t.charAt(n+1)===e;return i&&n++,i},x=function(e){var t=_(e),s="@"===e?14:"!"===e?20:"y"===e&&t?4:"o"===e?3:2,n="y"===e?s:1,a=RegExp("^\\d{"+n+","+s+"}"),o=i.substring(h).match(a);if(!o)throw"Missing number at position "+h;return h+=o[0].length,parseInt(o[0],10)},w=function(t,s,n){var a=-1,o=e.map(_(t)?n:s,function(e,t){return[[t,e]]}).sort(function(e,t){return-(e[1].length-t[1].length)});if(e.each(o,function(e,t){var s=t[1];return i.substr(h,s.length).toLowerCase()===s.toLowerCase()?(a=t[0],h+=s.length,!1):void 0}),-1!==a)return a+1;throw"Unknown name at position "+h},k=function(){if(i.charAt(h)!==t.charAt(n))throw"Unexpected literal at position "+h;h++};for(n=0;t.length>n;n++)if(b)"'"!==t.charAt(n)||_("'")?k():b=!1;else switch(t.charAt(n)){case"d":v=x("d");break;case"D":w("D",d,c);break;case"o":y=x("o");break;case"m":g=x("m");break;case"M":g=w("M",p,f);break;case"y":m=x("y");break;case"@":r=new Date(x("@")),m=r.getFullYear(),g=r.getMonth()+1,v=r.getDate();break;case"!":r=new Date((x("!")-this._ticksTo1970)/1e4),m=r.getFullYear(),g=r.getMonth()+1,v=r.getDate();break;case"'":_("'")?k():b=!0;break;default:k()}if(i.length>h&&(o=i.substr(h),!/^\s+/.test(o)))throw"Extra/unparsed characters found in date: "+o;if(-1===m?m=(new Date).getFullYear():100>m&&(m+=(new Date).getFullYear()-(new Date).getFullYear()%100+(u>=m?0:-100)),y>-1)for(g=1,v=y;;){if(a=this._getDaysInMonth(m,g-1),a>=v)break;g++,v-=a}if(r=this._daylightSavingAdjust(new Date(m,g-1,v)),r.getFullYear()!==m||r.getMonth()+1!==g||r.getDate()!==v)throw"Invalid date";return r},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(e,t,i){if(!t)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,a=(i?i.dayNames:null)||this._defaults.dayNames,o=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,r=(i?i.monthNames:null)||this._defaults.monthNames,h=function(t){var i=e.length>s+1&&e.charAt(s+1)===t;return i&&s++,i},l=function(e,t,i){var s=""+t;if(h(e))for(;i>s.length;)s="0"+s;return s},u=function(e,t,i,s){return h(e)?s[t]:i[t]},d="",c=!1;if(t)for(s=0;e.length>s;s++)if(c)"'"!==e.charAt(s)||h("'")?d+=e.charAt(s):c=!1;else switch(e.charAt(s)){case"d":d+=l("d",t.getDate(),2);break;case"D":d+=u("D",t.getDay(),n,a);break;case"o":d+=l("o",Math.round((new Date(t.getFullYear(),t.getMonth(),t.getDate()).getTime()-new Date(t.getFullYear(),0,0).getTime())/864e5),3);break;case"m":d+=l("m",t.getMonth()+1,2);break;case"M":d+=u("M",t.getMonth(),o,r);break;case"y":d+=h("y")?t.getFullYear():(10>t.getYear()%100?"0":"")+t.getYear()%100;break;case"@":d+=t.getTime();break;case"!":d+=1e4*t.getTime()+this._ticksTo1970;break;case"'":h("'")?d+="'":c=!0;break;default:d+=e.charAt(s)}return d},_possibleChars:function(e){var t,i="",s=!1,n=function(i){var s=e.length>t+1&&e.charAt(t+1)===i;return s&&t++,s};for(t=0;e.length>t;t++)if(s)"'"!==e.charAt(t)||n("'")?i+=e.charAt(t):s=!1;else switch(e.charAt(t)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=e.charAt(t)}return i},_get:function(e,t){return void 0!==e.settings[t]?e.settings[t]:this._defaults[t]},_setDateFromField:function(e,t){if(e.input.val()!==e.lastVal){var i=this._get(e,"dateFormat"),s=e.lastVal=e.input?e.input.val():null,n=this._getDefaultDate(e),a=n,o=this._getFormatConfig(e);try{a=this.parseDate(i,s,o)||n}catch(r){s=t?"":s}e.selectedDay=a.getDate(),e.drawMonth=e.selectedMonth=a.getMonth(),e.drawYear=e.selectedYear=a.getFullYear(),e.currentDay=s?a.getDate():0,e.currentMonth=s?a.getMonth():0,e.currentYear=s?a.getFullYear():0,this._adjustInstDate(e)}},_getDefaultDate:function(e){return this._restrictMinMax(e,this._determineDate(e,this._get(e,"defaultDate"),new Date))},_determineDate:function(t,i,s){var n=function(e){var t=new Date;return t.setDate(t.getDate()+e),t},a=function(i){try{return e.datepicker.parseDate(e.datepicker._get(t,"dateFormat"),i,e.datepicker._getFormatConfig(t))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?e.datepicker._getDate(t):null)||new Date,a=n.getFullYear(),o=n.getMonth(),r=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":r+=parseInt(l[1],10);break;case"w":case"W":r+=7*parseInt(l[1],10);break;case"m":case"M":o+=parseInt(l[1],10),r=Math.min(r,e.datepicker._getDaysInMonth(a,o));break;case"y":case"Y":a+=parseInt(l[1],10),r=Math.min(r,e.datepicker._getDaysInMonth(a,o))}l=h.exec(i)}return new Date(a,o,r)},o=null==i||""===i?s:"string"==typeof i?a(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return o=o&&"Invalid Date"==""+o?s:o,o&&(o.setHours(0),o.setMinutes(0),o.setSeconds(0),o.setMilliseconds(0)),this._daylightSavingAdjust(o)},_daylightSavingAdjust:function(e){return e?(e.setHours(e.getHours()>12?e.getHours()+2:0),e):null},_setDate:function(e,t,i){var s=!t,n=e.selectedMonth,a=e.selectedYear,o=this._restrictMinMax(e,this._determineDate(e,t,new Date));e.selectedDay=e.currentDay=o.getDate(),e.drawMonth=e.selectedMonth=e.currentMonth=o.getMonth(),e.drawYear=e.selectedYear=e.currentYear=o.getFullYear(),n===e.selectedMonth&&a===e.selectedYear||i||this._notifyChange(e),this._adjustInstDate(e),e.input&&e.input.val(s?"":this._formatDate(e))},_getDate:function(e){var t=!e.currentYear||e.input&&""===e.input.val()?null:this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return t},_attachHandlers:function(t){var i=this._get(t,"stepMonths"),s="#"+t.id.replace(/\\\\/g,"\\");t.dpDiv.find("[data-handler]").map(function(){var t={prev:function(){e.datepicker._adjustDate(s,-i,"M")},next:function(){e.datepicker._adjustDate(s,+i,"M")},hide:function(){e.datepicker._hideDatepicker()},today:function(){e.datepicker._gotoToday(s)},selectDay:function(){return e.datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return e.datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return e.datepicker._selectMonthYear(s,this,"Y"),!1}};e(this).bind(this.getAttribute("data-event"),t[this.getAttribute("data-handler")])})},_generateHTML:function(e){var t,i,s,n,a,o,r,h,l,u,d,c,p,f,m,g,v,y,b,_,x,w,k,T,D,S,M,C,N,A,P,I,H,z,F,E,O,j,W,L=new Date,R=this._daylightSavingAdjust(new Date(L.getFullYear(),L.getMonth(),L.getDate())),Y=this._get(e,"isRTL"),B=this._get(e,"showButtonPanel"),J=this._get(e,"hideIfNoPrevNext"),q=this._get(e,"navigationAsDateFormat"),K=this._getNumberOfMonths(e),V=this._get(e,"showCurrentAtPos"),U=this._get(e,"stepMonths"),Q=1!==K[0]||1!==K[1],G=this._daylightSavingAdjust(e.currentDay?new Date(e.currentYear,e.currentMonth,e.currentDay):new Date(9999,9,9)),X=this._getMinMaxDate(e,"min"),$=this._getMinMaxDate(e,"max"),Z=e.drawMonth-V,et=e.drawYear;if(0>Z&&(Z+=12,et--),$)for(t=this._daylightSavingAdjust(new Date($.getFullYear(),$.getMonth()-K[0]*K[1]+1,$.getDate())),t=X&&X>t?X:t;this._daylightSavingAdjust(new Date(et,Z,1))>t;)Z--,0>Z&&(Z=11,et--);for(e.drawMonth=Z,e.drawYear=et,i=this._get(e,"prevText"),i=q?this.formatDate(i,this._daylightSavingAdjust(new Date(et,Z-U,1)),this._getFormatConfig(e)):i,s=this._canAdjustMonth(e,-1,et,Z)?"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>":J?"":"<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>",n=this._get(e,"nextText"),n=q?this.formatDate(n,this._daylightSavingAdjust(new Date(et,Z+U,1)),this._getFormatConfig(e)):n,a=this._canAdjustMonth(e,1,et,Z)?"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>":J?"":"<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>",o=this._get(e,"currentText"),r=this._get(e,"gotoCurrent")&&e.currentDay?G:R,o=q?this.formatDate(o,r,this._getFormatConfig(e)):o,h=e.inline?"":"<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>"+this._get(e,"closeText")+"</button>",l=B?"<div class='ui-datepicker-buttonpane ui-widget-content'>"+(Y?h:"")+(this._isInRange(e,r)?"<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'>"+o+"</button>":"")+(Y?"":h)+"</div>":"",u=parseInt(this._get(e,"firstDay"),10),u=isNaN(u)?0:u,d=this._get(e,"showWeek"),c=this._get(e,"dayNames"),p=this._get(e,"dayNamesMin"),f=this._get(e,"monthNames"),m=this._get(e,"monthNamesShort"),g=this._get(e,"beforeShowDay"),v=this._get(e,"showOtherMonths"),y=this._get(e,"selectOtherMonths"),b=this._getDefaultDate(e),_="",w=0;K[0]>w;w++){for(k="",this.maxRows=4,T=0;K[1]>T;T++){if(D=this._daylightSavingAdjust(new Date(et,Z,e.selectedDay)),S=" ui-corner-all",M="",Q){if(M+="<div class='ui-datepicker-group",K[1]>1)switch(T){case 0:M+=" ui-datepicker-group-first",S=" ui-corner-"+(Y?"right":"left");break;case K[1]-1:M+=" ui-datepicker-group-last",S=" ui-corner-"+(Y?"left":"right");break;default:M+=" ui-datepicker-group-middle",S=""}M+="'>"}for(M+="<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix"+S+"'>"+(/all|left/.test(S)&&0===w?Y?a:s:"")+(/all|right/.test(S)&&0===w?Y?s:a:"")+this._generateMonthYearHeader(e,Z,et,X,$,w>0||T>0,f,m)+"</div><table class='ui-datepicker-calendar'><thead>"+"<tr>",C=d?"<th class='ui-datepicker-week-col'>"+this._get(e,"weekHeader")+"</th>":"",x=0;7>x;x++)N=(x+u)%7,C+="<th scope='col'"+((x+u+6)%7>=5?" class='ui-datepicker-week-end'":"")+">"+"<span title='"+c[N]+"'>"+p[N]+"</span></th>";for(M+=C+"</tr></thead><tbody>",A=this._getDaysInMonth(et,Z),et===e.selectedYear&&Z===e.selectedMonth&&(e.selectedDay=Math.min(e.selectedDay,A)),P=(this._getFirstDayOfMonth(et,Z)-u+7)%7,I=Math.ceil((P+A)/7),H=Q?this.maxRows>I?this.maxRows:I:I,this.maxRows=H,z=this._daylightSavingAdjust(new Date(et,Z,1-P)),F=0;H>F;F++){for(M+="<tr>",E=d?"<td class='ui-datepicker-week-col'>"+this._get(e,"calculateWeek")(z)+"</td>":"",x=0;7>x;x++)O=g?g.apply(e.input?e.input[0]:null,[z]):[!0,""],j=z.getMonth()!==Z,W=j&&!y||!O[0]||X&&X>z||$&&z>$,E+="<td class='"+((x+u+6)%7>=5?" ui-datepicker-week-end":"")+(j?" ui-datepicker-other-month":"")+(z.getTime()===D.getTime()&&Z===e.selectedMonth&&e._keyEvent||b.getTime()===z.getTime()&&b.getTime()===D.getTime()?" "+this._dayOverClass:"")+(W?" "+this._unselectableClass+" ui-state-disabled":"")+(j&&!v?"":" "+O[1]+(z.getTime()===G.getTime()?" "+this._currentClass:"")+(z.getTime()===R.getTime()?" ui-datepicker-today":""))+"'"+(j&&!v||!O[2]?"":" title='"+O[2].replace(/'/g,"&#39;")+"'")+(W?"":" data-handler='selectDay' data-event='click' data-month='"+z.getMonth()+"' data-year='"+z.getFullYear()+"'")+">"+(j&&!v?"&#xa0;":W?"<span class='ui-state-default'>"+z.getDate()+"</span>":"<a class='ui-state-default"+(z.getTime()===R.getTime()?" ui-state-highlight":"")+(z.getTime()===G.getTime()?" ui-state-active":"")+(j?" ui-priority-secondary":"")+"' href='#'>"+z.getDate()+"</a>")+"</td>",z.setDate(z.getDate()+1),z=this._daylightSavingAdjust(z);M+=E+"</tr>"}Z++,Z>11&&(Z=0,et++),M+="</tbody></table>"+(Q?"</div>"+(K[0]>0&&T===K[1]-1?"<div class='ui-datepicker-row-break'></div>":""):""),k+=M}_+=k}return _+=l,e._keyEvent=!1,_},_generateMonthYearHeader:function(e,t,i,s,n,a,o,r){var h,l,u,d,c,p,f,m,g=this._get(e,"changeMonth"),v=this._get(e,"changeYear"),y=this._get(e,"showMonthAfterYear"),b="<div class='ui-datepicker-title'>",_="";if(a||!g)_+="<span class='ui-datepicker-month'>"+o[t]+"</span>";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,_+="<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>",u=0;12>u;u++)(!h||u>=s.getMonth())&&(!l||n.getMonth()>=u)&&(_+="<option value='"+u+"'"+(u===t?" selected='selected'":"")+">"+r[u]+"</option>");_+="</select>"}if(y||(b+=_+(!a&&g&&v?"":"&#xa0;")),!e.yearshtml)if(e.yearshtml="",a||!v)b+="<span class='ui-datepicker-year'>"+i+"</span>";else{for(d=this._get(e,"yearRange").split(":"),c=(new Date).getFullYear(),p=function(e){var t=e.match(/c[+\-].*/)?i+parseInt(e.substring(1),10):e.match(/[+\-].*/)?c+parseInt(e,10):parseInt(e,10);return isNaN(t)?c:t},f=p(d[0]),m=Math.max(f,p(d[1]||"")),f=s?Math.max(f,s.getFullYear()):f,m=n?Math.min(m,n.getFullYear()):m,e.yearshtml+="<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";m>=f;f++)e.yearshtml+="<option value='"+f+"'"+(f===i?" selected='selected'":"")+">"+f+"</option>";e.yearshtml+="</select>",b+=e.yearshtml,e.yearshtml=null}return b+=this._get(e,"yearSuffix"),y&&(b+=(!a&&g&&v?"":"&#xa0;")+_),b+="</div>"},_adjustInstDate:function(e,t,i){var s=e.drawYear+("Y"===i?t:0),n=e.drawMonth+("M"===i?t:0),a=Math.min(e.selectedDay,this._getDaysInMonth(s,n))+("D"===i?t:0),o=this._restrictMinMax(e,this._daylightSavingAdjust(new Date(s,n,a)));e.selectedDay=o.getDate(),e.drawMonth=e.selectedMonth=o.getMonth(),e.drawYear=e.selectedYear=o.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(e)},_restrictMinMax:function(e,t){var i=this._getMinMaxDate(e,"min"),s=this._getMinMaxDate(e,"max"),n=i&&i>t?i:t;return s&&n>s?s:n},_notifyChange:function(e){var t=this._get(e,"onChangeMonthYear");t&&t.apply(e.input?e.input[0]:null,[e.selectedYear,e.selectedMonth+1,e])},_getNumberOfMonths:function(e){var t=this._get(e,"numberOfMonths");return null==t?[1,1]:"number"==typeof t?[1,t]:t},_getMinMaxDate:function(e,t){return this._determineDate(e,this._get(e,t+"Date"),null)},_getDaysInMonth:function(e,t){return 32-this._daylightSavingAdjust(new Date(e,t,32)).getDate()},_getFirstDayOfMonth:function(e,t){return new Date(e,t,1).getDay()},_canAdjustMonth:function(e,t,i,s){var n=this._getNumberOfMonths(e),a=this._daylightSavingAdjust(new Date(i,s+(0>t?t:n[0]*n[1]),1));return 0>t&&a.setDate(this._getDaysInMonth(a.getFullYear(),a.getMonth())),this._isInRange(e,a)},_isInRange:function(e,t){var i,s,n=this._getMinMaxDate(e,"min"),a=this._getMinMaxDate(e,"max"),o=null,r=null,h=this._get(e,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),o=parseInt(i[0],10),r=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(o+=s),i[1].match(/[+\-].*/)&&(r+=s)),(!n||t.getTime()>=n.getTime())&&(!a||t.getTime()<=a.getTime())&&(!o||t.getFullYear()>=o)&&(!r||r>=t.getFullYear())},_getFormatConfig:function(e){var t=this._get(e,"shortYearCutoff");return t="string"!=typeof t?t:(new Date).getFullYear()%100+parseInt(t,10),{shortYearCutoff:t,dayNamesShort:this._get(e,"dayNamesShort"),dayNames:this._get(e,"dayNames"),monthNamesShort:this._get(e,"monthNamesShort"),monthNames:this._get(e,"monthNames")}},_formatDate:function(e,t,i,s){t||(e.currentDay=e.selectedDay,e.currentMonth=e.selectedMonth,e.currentYear=e.selectedYear);var n=t?"object"==typeof t?t:this._daylightSavingAdjust(new Date(s,i,t)):this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return this.formatDate(this._get(e,"dateFormat"),n,this._getFormatConfig(e))}}),e.fn.datepicker=function(t){if(!this.length)return this;e.datepicker.initialized||(e(document).mousedown(e.datepicker._checkExternalClick),e.datepicker.initialized=!0),0===e("#"+e.datepicker._mainDivId).length&&e("body").append(e.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof t||"isDisabled"!==t&&"getDate"!==t&&"widget"!==t?"option"===t&&2===arguments.length&&"string"==typeof arguments[1]?e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof t?e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this].concat(i)):e.datepicker._attachDatepicker(this,t)}):e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this[0]].concat(i))},e.datepicker=new n,e.datepicker.initialized=!1,e.datepicker.uuid=(new Date).getTime(),e.datepicker.version="1.11.4",e.datepicker,e.widget("ui.dialog",{version:"1.11.4",options:{appendTo:"body",autoOpen:!0,buttons:[],closeOnEscape:!0,closeText:"Close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(t){var i=e(this).css(t).offset().top;0>i&&e(this).css("top",t.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},sizeRelatedOptions:{buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},resizableRelatedOptions:{maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),this.options.title=this.options.title||this.originalTitle,this._createWrapper(),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(this.uiDialog),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&e.fn.draggable&&this._makeDraggable(),this.options.resizable&&e.fn.resizable&&this._makeResizable(),this._isOpen=!1,this._trackFocus()},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var t=this.options.appendTo;return t&&(t.jquery||t.nodeType)?e(t):this.document.find(t||"body").eq(0)},_destroy:function(){var e,t=this.originalPosition;this._untrackInstance(),this._destroyOverlay(),this.element.removeUniqueId().removeClass("ui-dialog-content ui-widget-content").css(this.originalCss).detach(),this.uiDialog.stop(!0,!0).remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),e=t.parent.children().eq(t.index),e.length&&e[0]!==this.element[0]?e.before(this.element):t.parent.append(this.element)},widget:function(){return this.uiDialog},disable:e.noop,enable:e.noop,close:function(t){var i,s=this;if(this._isOpen&&this._trigger("beforeClose",t)!==!1){if(this._isOpen=!1,this._focusedElement=null,this._destroyOverlay(),this._untrackInstance(),!this.opener.filter(":focusable").focus().length)try{i=this.document[0].activeElement,i&&"body"!==i.nodeName.toLowerCase()&&e(i).blur()}catch(n){}this._hide(this.uiDialog,this.options.hide,function(){s._trigger("close",t)})}},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(t,i){var s=!1,n=this.uiDialog.siblings(".ui-front:visible").map(function(){return+e(this).css("z-index")}).get(),a=Math.max.apply(null,n);return a>=+this.uiDialog.css("z-index")&&(this.uiDialog.css("z-index",a+1),s=!0),s&&!i&&this._trigger("focus",t),s},open:function(){var t=this;
+return this._isOpen?(this._moveToTop()&&this._focusTabbable(),void 0):(this._isOpen=!0,this.opener=e(this.document[0].activeElement),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this.overlay&&this.overlay.css("z-index",this.uiDialog.css("z-index")-1),this._show(this.uiDialog,this.options.show,function(){t._focusTabbable(),t._trigger("focus")}),this._makeFocusTarget(),this._trigger("open"),void 0)},_focusTabbable:function(){var e=this._focusedElement;e||(e=this.element.find("[autofocus]")),e.length||(e=this.element.find(":tabbable")),e.length||(e=this.uiDialogButtonPane.find(":tabbable")),e.length||(e=this.uiDialogTitlebarClose.filter(":tabbable")),e.length||(e=this.uiDialog),e.eq(0).focus()},_keepFocus:function(t){function i(){var t=this.document[0].activeElement,i=this.uiDialog[0]===t||e.contains(this.uiDialog[0],t);i||this._focusTabbable()}t.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=e("<div>").addClass("ui-dialog ui-widget ui-widget-content ui-corner-all ui-front "+this.options.dialogClass).hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._on(this.uiDialog,{keydown:function(t){if(this.options.closeOnEscape&&!t.isDefaultPrevented()&&t.keyCode&&t.keyCode===e.ui.keyCode.ESCAPE)return t.preventDefault(),this.close(t),void 0;if(t.keyCode===e.ui.keyCode.TAB&&!t.isDefaultPrevented()){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");t.target!==n[0]&&t.target!==this.uiDialog[0]||t.shiftKey?t.target!==s[0]&&t.target!==this.uiDialog[0]||!t.shiftKey||(this._delay(function(){n.focus()}),t.preventDefault()):(this._delay(function(){s.focus()}),t.preventDefault())}},mousedown:function(e){this._moveToTop(e)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var t;this.uiDialogTitlebar=e("<div>").addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(this.uiDialog),this._on(this.uiDialogTitlebar,{mousedown:function(t){e(t.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.focus()}}),this.uiDialogTitlebarClose=e("<button type='button'></button>").button({label:this.options.closeText,icons:{primary:"ui-icon-closethick"},text:!1}).addClass("ui-dialog-titlebar-close").appendTo(this.uiDialogTitlebar),this._on(this.uiDialogTitlebarClose,{click:function(e){e.preventDefault(),this.close(e)}}),t=e("<span>").uniqueId().addClass("ui-dialog-title").prependTo(this.uiDialogTitlebar),this._title(t),this.uiDialog.attr({"aria-labelledby":t.attr("id")})},_title:function(e){this.options.title||e.html("&#160;"),e.text(this.options.title)},_createButtonPane:function(){this.uiDialogButtonPane=e("<div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),this.uiButtonSet=e("<div>").addClass("ui-dialog-buttonset").appendTo(this.uiDialogButtonPane),this._createButtons()},_createButtons:function(){var t=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),e.isEmptyObject(i)||e.isArray(i)&&!i.length?(this.uiDialog.removeClass("ui-dialog-buttons"),void 0):(e.each(i,function(i,s){var n,a;s=e.isFunction(s)?{click:s,text:i}:s,s=e.extend({type:"button"},s),n=s.click,s.click=function(){n.apply(t.element[0],arguments)},a={icons:s.icons,text:s.showText},delete s.icons,delete s.showText,e("<button></button>",s).button(a).appendTo(t.uiButtonSet)}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),void 0)},_makeDraggable:function(){function t(e){return{position:e.position,offset:e.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){e(this).addClass("ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,t(n))},drag:function(e,s){i._trigger("drag",e,t(s))},stop:function(n,a){var o=a.offset.left-i.document.scrollLeft(),r=a.offset.top-i.document.scrollTop();s.position={my:"left top",at:"left"+(o>=0?"+":"")+o+" "+"top"+(r>=0?"+":"")+r,of:i.window},e(this).removeClass("ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,t(a))}})},_makeResizable:function(){function t(e){return{originalPosition:e.originalPosition,originalSize:e.originalSize,position:e.position,size:e.size}}var i=this,s=this.options,n=s.resizable,a=this.uiDialog.css("position"),o="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:o,start:function(s,n){e(this).addClass("ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,t(n))},resize:function(e,s){i._trigger("resize",e,t(s))},stop:function(n,a){var o=i.uiDialog.offset(),r=o.left-i.document.scrollLeft(),h=o.top-i.document.scrollTop();s.height=i.uiDialog.height(),s.width=i.uiDialog.width(),s.position={my:"left top",at:"left"+(r>=0?"+":"")+r+" "+"top"+(h>=0?"+":"")+h,of:i.window},e(this).removeClass("ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,t(a))}}).css("position",a)},_trackFocus:function(){this._on(this.widget(),{focusin:function(t){this._makeFocusTarget(),this._focusedElement=e(t.target)}})},_makeFocusTarget:function(){this._untrackInstance(),this._trackingInstances().unshift(this)},_untrackInstance:function(){var t=this._trackingInstances(),i=e.inArray(this,t);-1!==i&&t.splice(i,1)},_trackingInstances:function(){var e=this.document.data("ui-dialog-instances");return e||(e=[],this.document.data("ui-dialog-instances",e)),e},_minHeight:function(){var e=this.options;return"auto"===e.height?e.minHeight:Math.min(e.minHeight,e.height)},_position:function(){var e=this.uiDialog.is(":visible");e||this.uiDialog.show(),this.uiDialog.position(this.options.position),e||this.uiDialog.hide()},_setOptions:function(t){var i=this,s=!1,n={};e.each(t,function(e,t){i._setOption(e,t),e in i.sizeRelatedOptions&&(s=!0),e in i.resizableRelatedOptions&&(n[e]=t)}),s&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",n)},_setOption:function(e,t){var i,s,n=this.uiDialog;"dialogClass"===e&&n.removeClass(this.options.dialogClass).addClass(t),"disabled"!==e&&(this._super(e,t),"appendTo"===e&&this.uiDialog.appendTo(this._appendTo()),"buttons"===e&&this._createButtons(),"closeText"===e&&this.uiDialogTitlebarClose.button({label:""+t}),"draggable"===e&&(i=n.is(":data(ui-draggable)"),i&&!t&&n.draggable("destroy"),!i&&t&&this._makeDraggable()),"position"===e&&this._position(),"resizable"===e&&(s=n.is(":data(ui-resizable)"),s&&!t&&n.resizable("destroy"),s&&"string"==typeof t&&n.resizable("option","handles",t),s||t===!1||this._makeResizable()),"title"===e&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var e,t,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),e=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),t=Math.max(0,s.minHeight-e),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-e):"none","auto"===s.height?this.element.css({minHeight:t,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-e)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var t=e(this);return e("<div>").css({position:"absolute",width:t.outerWidth(),height:t.outerHeight()}).appendTo(t.parent()).offset(t.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(t){return e(t.target).closest(".ui-dialog").length?!0:!!e(t.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var t=!0;this._delay(function(){t=!1}),this.document.data("ui-dialog-overlays")||this._on(this.document,{focusin:function(e){t||this._allowInteraction(e)||(e.preventDefault(),this._trackingInstances()[0]._focusTabbable())}}),this.overlay=e("<div>").addClass("ui-widget-overlay ui-front").appendTo(this._appendTo()),this._on(this.overlay,{mousedown:"_keepFocus"}),this.document.data("ui-dialog-overlays",(this.document.data("ui-dialog-overlays")||0)+1)}},_destroyOverlay:function(){if(this.options.modal&&this.overlay){var e=this.document.data("ui-dialog-overlays")-1;e?this.document.data("ui-dialog-overlays",e):this.document.unbind("focusin").removeData("ui-dialog-overlays"),this.overlay.remove(),this.overlay=null}}}),e.widget("ui.progressbar",{version:"1.11.4",options:{max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min}),this.valueDiv=e("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this._refreshValue()},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(e){return void 0===e?this.options.value:(this.options.value=this._constrainedValue(e),this._refreshValue(),void 0)},_constrainedValue:function(e){return void 0===e&&(e=this.options.value),this.indeterminate=e===!1,"number"!=typeof e&&(e=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,e))},_setOptions:function(e){var t=e.value;delete e.value,this._super(e),this.options.value=this._constrainedValue(t),this._refreshValue()},_setOption:function(e,t){"max"===e&&(t=Math.max(this.min,t)),"disabled"===e&&this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this._super(e,t)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var t=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||t>this.min).toggleClass("ui-corner-right",t===this.options.max).width(i.toFixed(0)+"%"),this.element.toggleClass("ui-progressbar-indeterminate",this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=e("<div class='ui-progressbar-overlay'></div>").appendTo(this.valueDiv))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":t}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==t&&(this.oldValue=t,this._trigger("change")),t===this.options.max&&this._trigger("complete")}}),e.widget("ui.selectmenu",{version:"1.11.4",defaultElement:"<select>",options:{appendTo:null,disabled:null,icons:{button:"ui-icon-triangle-1-s"},position:{my:"left top",at:"left bottom",collision:"none"},width:null,change:null,close:null,focus:null,open:null,select:null},_create:function(){var e=this.element.uniqueId().attr("id");this.ids={element:e,button:e+"-button",menu:e+"-menu"},this._drawButton(),this._drawMenu(),this.options.disabled&&this.disable()},_drawButton:function(){var t=this;this.label=e("label[for='"+this.ids.element+"']").attr("for",this.ids.button),this._on(this.label,{click:function(e){this.button.focus(),e.preventDefault()}}),this.element.hide(),this.button=e("<span>",{"class":"ui-selectmenu-button ui-widget ui-state-default ui-corner-all",tabindex:this.options.disabled?-1:0,id:this.ids.button,role:"combobox","aria-expanded":"false","aria-autocomplete":"list","aria-owns":this.ids.menu,"aria-haspopup":"true"}).insertAfter(this.element),e("<span>",{"class":"ui-icon "+this.options.icons.button}).prependTo(this.button),this.buttonText=e("<span>",{"class":"ui-selectmenu-text"}).appendTo(this.button),this._setText(this.buttonText,this.element.find("option:selected").text()),this._resizeButton(),this._on(this.button,this._buttonEvents),this.button.one("focusin",function(){t.menuItems||t._refreshMenu()}),this._hoverable(this.button),this._focusable(this.button)},_drawMenu:function(){var t=this;this.menu=e("<ul>",{"aria-hidden":"true","aria-labelledby":this.ids.button,id:this.ids.menu}),this.menuWrap=e("<div>",{"class":"ui-selectmenu-menu ui-front"}).append(this.menu).appendTo(this._appendTo()),this.menuInstance=this.menu.menu({role:"listbox",select:function(e,i){e.preventDefault(),t._setSelection(),t._select(i.item.data("ui-selectmenu-item"),e)},focus:function(e,i){var s=i.item.data("ui-selectmenu-item");null!=t.focusIndex&&s.index!==t.focusIndex&&(t._trigger("focus",e,{item:s}),t.isOpen||t._select(s,e)),t.focusIndex=s.index,t.button.attr("aria-activedescendant",t.menuItems.eq(s.index).attr("id"))}}).menu("instance"),this.menu.addClass("ui-corner-bottom").removeClass("ui-corner-all"),this.menuInstance._off(this.menu,"mouseleave"),this.menuInstance._closeOnDocumentClick=function(){return!1},this.menuInstance._isDivider=function(){return!1}},refresh:function(){this._refreshMenu(),this._setText(this.buttonText,this._getSelectedItem().text()),this.options.width||this._resizeButton()},_refreshMenu:function(){this.menu.empty();var e,t=this.element.find("option");t.length&&(this._parseOptions(t),this._renderMenu(this.menu,this.items),this.menuInstance.refresh(),this.menuItems=this.menu.find("li").not(".ui-selectmenu-optgroup"),e=this._getSelectedItem(),this.menuInstance.focus(null,e),this._setAria(e.data("ui-selectmenu-item")),this._setOption("disabled",this.element.prop("disabled")))},open:function(e){this.options.disabled||(this.menuItems?(this.menu.find(".ui-state-focus").removeClass("ui-state-focus"),this.menuInstance.focus(null,this._getSelectedItem())):this._refreshMenu(),this.isOpen=!0,this._toggleAttr(),this._resizeMenu(),this._position(),this._on(this.document,this._documentClick),this._trigger("open",e))},_position:function(){this.menuWrap.position(e.extend({of:this.button},this.options.position))},close:function(e){this.isOpen&&(this.isOpen=!1,this._toggleAttr(),this.range=null,this._off(this.document),this._trigger("close",e))},widget:function(){return this.button},menuWidget:function(){return this.menu},_renderMenu:function(t,i){var s=this,n="";e.each(i,function(i,a){a.optgroup!==n&&(e("<li>",{"class":"ui-selectmenu-optgroup ui-menu-divider"+(a.element.parent("optgroup").prop("disabled")?" ui-state-disabled":""),text:a.optgroup}).appendTo(t),n=a.optgroup),s._renderItemData(t,a)})},_renderItemData:function(e,t){return this._renderItem(e,t).data("ui-selectmenu-item",t)},_renderItem:function(t,i){var s=e("<li>");return i.disabled&&s.addClass("ui-state-disabled"),this._setText(s,i.label),s.appendTo(t)},_setText:function(e,t){t?e.text(t):e.html("&#160;")},_move:function(e,t){var i,s,n=".ui-menu-item";this.isOpen?i=this.menuItems.eq(this.focusIndex):(i=this.menuItems.eq(this.element[0].selectedIndex),n+=":not(.ui-state-disabled)"),s="first"===e||"last"===e?i["first"===e?"prevAll":"nextAll"](n).eq(-1):i[e+"All"](n).eq(0),s.length&&this.menuInstance.focus(t,s)},_getSelectedItem:function(){return this.menuItems.eq(this.element[0].selectedIndex)},_toggle:function(e){this[this.isOpen?"close":"open"](e)},_setSelection:function(){var e;this.range&&(window.getSelection?(e=window.getSelection(),e.removeAllRanges(),e.addRange(this.range)):this.range.select(),this.button.focus())},_documentClick:{mousedown:function(t){this.isOpen&&(e(t.target).closest(".ui-selectmenu-menu, #"+this.ids.button).length||this.close(t))}},_buttonEvents:{mousedown:function(){var e;window.getSelection?(e=window.getSelection(),e.rangeCount&&(this.range=e.getRangeAt(0))):this.range=document.selection.createRange()},click:function(e){this._setSelection(),this._toggle(e)},keydown:function(t){var i=!0;switch(t.keyCode){case e.ui.keyCode.TAB:case e.ui.keyCode.ESCAPE:this.close(t),i=!1;break;case e.ui.keyCode.ENTER:this.isOpen&&this._selectFocusedItem(t);break;case e.ui.keyCode.UP:t.altKey?this._toggle(t):this._move("prev",t);break;case e.ui.keyCode.DOWN:t.altKey?this._toggle(t):this._move("next",t);break;case e.ui.keyCode.SPACE:this.isOpen?this._selectFocusedItem(t):this._toggle(t);break;case e.ui.keyCode.LEFT:this._move("prev",t);break;case e.ui.keyCode.RIGHT:this._move("next",t);break;case e.ui.keyCode.HOME:case e.ui.keyCode.PAGE_UP:this._move("first",t);break;case e.ui.keyCode.END:case e.ui.keyCode.PAGE_DOWN:this._move("last",t);break;default:this.menu.trigger(t),i=!1}i&&t.preventDefault()}},_selectFocusedItem:function(e){var t=this.menuItems.eq(this.focusIndex);t.hasClass("ui-state-disabled")||this._select(t.data("ui-selectmenu-item"),e)},_select:function(e,t){var i=this.element[0].selectedIndex;this.element[0].selectedIndex=e.index,this._setText(this.buttonText,e.label),this._setAria(e),this._trigger("select",t,{item:e}),e.index!==i&&this._trigger("change",t,{item:e}),this.close(t)},_setAria:function(e){var t=this.menuItems.eq(e.index).attr("id");this.button.attr({"aria-labelledby":t,"aria-activedescendant":t}),this.menu.attr("aria-activedescendant",t)},_setOption:function(e,t){"icons"===e&&this.button.find("span.ui-icon").removeClass(this.options.icons.button).addClass(t.button),this._super(e,t),"appendTo"===e&&this.menuWrap.appendTo(this._appendTo()),"disabled"===e&&(this.menuInstance.option("disabled",t),this.button.toggleClass("ui-state-disabled",t).attr("aria-disabled",t),this.element.prop("disabled",t),t?(this.button.attr("tabindex",-1),this.close()):this.button.attr("tabindex",0)),"width"===e&&this._resizeButton()},_appendTo:function(){var t=this.options.appendTo;return t&&(t=t.jquery||t.nodeType?e(t):this.document.find(t).eq(0)),t&&t[0]||(t=this.element.closest(".ui-front")),t.length||(t=this.document[0].body),t},_toggleAttr:function(){this.button.toggleClass("ui-corner-top",this.isOpen).toggleClass("ui-corner-all",!this.isOpen).attr("aria-expanded",this.isOpen),this.menuWrap.toggleClass("ui-selectmenu-open",this.isOpen),this.menu.attr("aria-hidden",!this.isOpen)},_resizeButton:function(){var e=this.options.width;e||(e=this.element.show().outerWidth(),this.element.hide()),this.button.outerWidth(e)},_resizeMenu:function(){this.menu.outerWidth(Math.max(this.button.outerWidth(),this.menu.width("").outerWidth()+1))},_getCreateOptions:function(){return{disabled:this.element.prop("disabled")}},_parseOptions:function(t){var i=[];t.each(function(t,s){var n=e(s),a=n.parent("optgroup");i.push({element:n,index:t,value:n.val(),label:n.text(),optgroup:a.attr("label")||"",disabled:a.prop("disabled")||n.prop("disabled")})}),this.items=i},_destroy:function(){this.menuWrap.remove(),this.button.remove(),this.element.show(),this.element.removeUniqueId(),this.label.attr("for",this.ids.element)}}),e.widget("ui.slider",e.ui.mouse,{version:"1.11.4",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},numPages:5,_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this._calculateNewMax(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"),this._refresh(),this._setOption("disabled",this.options.disabled),this._animateOff=!1},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var t,i,s=this.options,n=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),a="<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",o=[];for(i=s.values&&s.values.length||1,n.length>i&&(n.slice(i).remove(),n=n.slice(0,i)),t=n.length;i>t;t++)o.push(a);this.handles=n.add(e(o.join("")).appendTo(this.element)),this.handle=this.handles.eq(0),this.handles.each(function(t){e(this).data("ui-slider-handle-index",t)})},_createRange:function(){var t=this.options,i="";t.range?(t.range===!0&&(t.values?t.values.length&&2!==t.values.length?t.values=[t.values[0],t.values[0]]:e.isArray(t.values)&&(t.values=t.values.slice(0)):t.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?this.range.removeClass("ui-slider-range-min ui-slider-range-max").css({left:"",bottom:""}):(this.range=e("<div></div>").appendTo(this.element),i="ui-slider-range ui-widget-header ui-corner-all"),this.range.addClass(i+("min"===t.range||"max"===t.range?" ui-slider-range-"+t.range:""))):(this.range&&this.range.remove(),this.range=null)},_setupEvents:function(){this._off(this.handles),this._on(this.handles,this._handleEvents),this._hoverable(this.handles),this._focusable(this.handles)},_destroy:function(){this.handles.remove(),this.range&&this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-widget ui-widget-content ui-corner-all"),this._mouseDestroy()},_mouseCapture:function(t){var i,s,n,a,o,r,h,l,u=this,d=this.options;return d.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),i={x:t.pageX,y:t.pageY},s=this._normValueFromMouse(i),n=this._valueMax()-this._valueMin()+1,this.handles.each(function(t){var i=Math.abs(s-u.values(t));(n>i||n===i&&(t===u._lastChangedValue||u.values(t)===d.min))&&(n=i,a=e(this),o=t)}),r=this._start(t,o),r===!1?!1:(this._mouseSliding=!0,this._handleIndex=o,a.addClass("ui-state-active").focus(),h=a.offset(),l=!e(t.target).parents().addBack().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:t.pageX-h.left-a.width()/2,top:t.pageY-h.top-a.height()/2-(parseInt(a.css("borderTopWidth"),10)||0)-(parseInt(a.css("borderBottomWidth"),10)||0)+(parseInt(a.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(t,o,s),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(e){var t={x:e.pageX,y:e.pageY},i=this._normValueFromMouse(t);return this._slide(e,this._handleIndex,i),!1},_mouseStop:function(e){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(e,this._handleIndex),this._change(e,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation="vertical"===this.options.orientation?"vertical":"horizontal"},_normValueFromMouse:function(e){var t,i,s,n,a;return"horizontal"===this.orientation?(t=this.elementSize.width,i=e.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(t=this.elementSize.height,i=e.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),s=i/t,s>1&&(s=1),0>s&&(s=0),"vertical"===this.orientation&&(s=1-s),n=this._valueMax()-this._valueMin(),a=this._valueMin()+s*n,this._trimAlignValue(a)},_start:function(e,t){var i={handle:this.handles[t],value:this.value()};return this.options.values&&this.options.values.length&&(i.value=this.values(t),i.values=this.values()),this._trigger("start",e,i)},_slide:function(e,t,i){var s,n,a;this.options.values&&this.options.values.length?(s=this.values(t?0:1),2===this.options.values.length&&this.options.range===!0&&(0===t&&i>s||1===t&&s>i)&&(i=s),i!==this.values(t)&&(n=this.values(),n[t]=i,a=this._trigger("slide",e,{handle:this.handles[t],value:i,values:n}),s=this.values(t?0:1),a!==!1&&this.values(t,i))):i!==this.value()&&(a=this._trigger("slide",e,{handle:this.handles[t],value:i}),a!==!1&&this.value(i))},_stop:function(e,t){var i={handle:this.handles[t],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(t),i.values=this.values()),this._trigger("stop",e,i)},_change:function(e,t){if(!this._keySliding&&!this._mouseSliding){var i={handle:this.handles[t],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(t),i.values=this.values()),this._lastChangedValue=t,this._trigger("change",e,i)}},value:function(e){return arguments.length?(this.options.value=this._trimAlignValue(e),this._refreshValue(),this._change(null,0),void 0):this._value()},values:function(t,i){var s,n,a;if(arguments.length>1)return this.options.values[t]=this._trimAlignValue(i),this._refreshValue(),this._change(null,t),void 0;if(!arguments.length)return this._values();if(!e.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(t):this.value();for(s=this.options.values,n=arguments[0],a=0;s.length>a;a+=1)s[a]=this._trimAlignValue(n[a]),this._change(null,a);this._refreshValue()},_setOption:function(t,i){var s,n=0;switch("range"===t&&this.options.range===!0&&("min"===i?(this.options.value=this._values(0),this.options.values=null):"max"===i&&(this.options.value=this._values(this.options.values.length-1),this.options.values=null)),e.isArray(this.options.values)&&(n=this.options.values.length),"disabled"===t&&this.element.toggleClass("ui-state-disabled",!!i),this._super(t,i),t){case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue(),this.handles.css("horizontal"===i?"bottom":"left","");break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":for(this._animateOff=!0,this._refreshValue(),s=0;n>s;s+=1)this._change(null,s);this._animateOff=!1;break;case"step":case"min":case"max":this._animateOff=!0,this._calculateNewMax(),this._refreshValue(),this._animateOff=!1;break;case"range":this._animateOff=!0,this._refresh(),this._animateOff=!1}},_value:function(){var e=this.options.value;return e=this._trimAlignValue(e)},_values:function(e){var t,i,s;if(arguments.length)return t=this.options.values[e],t=this._trimAlignValue(t);if(this.options.values&&this.options.values.length){for(i=this.options.values.slice(),s=0;i.length>s;s+=1)i[s]=this._trimAlignValue(i[s]);return i}return[]},_trimAlignValue:function(e){if(this._valueMin()>=e)return this._valueMin();if(e>=this._valueMax())return this._valueMax();var t=this.options.step>0?this.options.step:1,i=(e-this._valueMin())%t,s=e-i;return 2*Math.abs(i)>=t&&(s+=i>0?t:-t),parseFloat(s.toFixed(5))},_calculateNewMax:function(){var e=this.options.max,t=this._valueMin(),i=this.options.step,s=Math.floor(+(e-t).toFixed(this._precision())/i)*i;e=s+t,this.max=parseFloat(e.toFixed(this._precision()))},_precision:function(){var e=this._precisionOf(this.options.step);return null!==this.options.min&&(e=Math.max(e,this._precisionOf(this.options.min))),e},_precisionOf:function(e){var t=""+e,i=t.indexOf(".");return-1===i?0:t.length-i-1},_valueMin:function(){return this.options.min},_valueMax:function(){return this.max},_refreshValue:function(){var t,i,s,n,a,o=this.options.range,r=this.options,h=this,l=this._animateOff?!1:r.animate,u={};this.options.values&&this.options.values.length?this.handles.each(function(s){i=100*((h.values(s)-h._valueMin())/(h._valueMax()-h._valueMin())),u["horizontal"===h.orientation?"left":"bottom"]=i+"%",e(this).stop(1,1)[l?"animate":"css"](u,r.animate),h.options.range===!0&&("horizontal"===h.orientation?(0===s&&h.range.stop(1,1)[l?"animate":"css"]({left:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({width:i-t+"%"},{queue:!1,duration:r.animate})):(0===s&&h.range.stop(1,1)[l?"animate":"css"]({bottom:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({height:i-t+"%"},{queue:!1,duration:r.animate}))),t=i}):(s=this.value(),n=this._valueMin(),a=this._valueMax(),i=a!==n?100*((s-n)/(a-n)):0,u["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[l?"animate":"css"](u,r.animate),"min"===o&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:i+"%"},r.animate),"max"===o&&"horizontal"===this.orientation&&this.range[l?"animate":"css"]({width:100-i+"%"},{queue:!1,duration:r.animate}),"min"===o&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:i+"%"},r.animate),"max"===o&&"vertical"===this.orientation&&this.range[l?"animate":"css"]({height:100-i+"%"},{queue:!1,duration:r.animate}))},_handleEvents:{keydown:function(t){var i,s,n,a,o=e(t.target).data("ui-slider-handle-index");switch(t.keyCode){case e.ui.keyCode.HOME:case e.ui.keyCode.END:case e.ui.keyCode.PAGE_UP:case e.ui.keyCode.PAGE_DOWN:case e.ui.keyCode.UP:case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:case e.ui.keyCode.LEFT:if(t.preventDefault(),!this._keySliding&&(this._keySliding=!0,e(t.target).addClass("ui-state-active"),i=this._start(t,o),i===!1))return}switch(a=this.options.step,s=n=this.options.values&&this.options.values.length?this.values(o):this.value(),t.keyCode){case e.ui.keyCode.HOME:n=this._valueMin();break;case e.ui.keyCode.END:n=this._valueMax();break;case e.ui.keyCode.PAGE_UP:n=this._trimAlignValue(s+(this._valueMax()-this._valueMin())/this.numPages);break;case e.ui.keyCode.PAGE_DOWN:n=this._trimAlignValue(s-(this._valueMax()-this._valueMin())/this.numPages);break;case e.ui.keyCode.UP:case e.ui.keyCode.RIGHT:if(s===this._valueMax())return;n=this._trimAlignValue(s+a);break;case e.ui.keyCode.DOWN:case e.ui.keyCode.LEFT:if(s===this._valueMin())return;n=this._trimAlignValue(s-a)}this._slide(t,o,n)},keyup:function(t){var i=e(t.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(t,i),this._change(t,i),e(t.target).removeClass("ui-state-active"))}}}),e.widget("ui.spinner",{version:"1.11.4",defaultElement:"<input>",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var t={},i=this.element;return e.each(["min","max","step"],function(e,s){var n=i.attr(s);void 0!==n&&n.length&&(t[s]=n)}),t},_events:{keydown:function(e){this._start(e)&&this._keydown(e)&&e.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(e){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",e),void 0)},mousewheel:function(e,t){if(t){if(!this.spinning&&!this._start(e))return!1;this._spin((t>0?1:-1)*this.options.step,e),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(e)},100),e.preventDefault()}},"mousedown .ui-spinner-button":function(t){function i(){var e=this.element[0]===this.document[0].activeElement;e||(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),t.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(t)!==!1&&this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(t){return e(t.currentTarget).hasClass("ui-state-active")?this._start(t)===!1?!1:(this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var e=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=e.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(.5*e.height())&&e.height()>0&&e.height(e.height()),this.options.disabled&&this.disable()
+},_keydown:function(t){var i=this.options,s=e.ui.keyCode;switch(t.keyCode){case s.UP:return this._repeat(null,1,t),!0;case s.DOWN:return this._repeat(null,-1,t),!0;case s.PAGE_UP:return this._repeat(null,i.page,t),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,t),!0}return!1},_uiSpinnerHtml:function(){return"<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"},_buttonHtml:function(){return"<a class='ui-spinner-button ui-spinner-up ui-corner-tr'><span class='ui-icon "+this.options.icons.up+"'>&#9650;</span>"+"</a>"+"<a class='ui-spinner-button ui-spinner-down ui-corner-br'>"+"<span class='ui-icon "+this.options.icons.down+"'>&#9660;</span>"+"</a>"},_start:function(e){return this.spinning||this._trigger("start",e)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(e,t,i){e=e||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,t,i)},e),this._spin(t*this.options.step,i)},_spin:function(e,t){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+e*this._increment(this.counter)),this.spinning&&this._trigger("spin",t,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(t){var i=this.options.incremental;return i?e.isFunction(i)?i(t):Math.floor(t*t*t/5e4-t*t/500+17*t/200+1):1},_precision:function(){var e=this._precisionOf(this.options.step);return null!==this.options.min&&(e=Math.max(e,this._precisionOf(this.options.min))),e},_precisionOf:function(e){var t=""+e,i=t.indexOf(".");return-1===i?0:t.length-i-1},_adjustValue:function(e){var t,i,s=this.options;return t=null!==s.min?s.min:0,i=e-t,i=Math.round(i/s.step)*s.step,e=t+i,e=parseFloat(e.toFixed(this._precision())),null!==s.max&&e>s.max?s.max:null!==s.min&&s.min>e?s.min:e},_stop:function(e){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",e))},_setOption:function(e,t){if("culture"===e||"numberFormat"===e){var i=this._parse(this.element.val());return this.options[e]=t,this.element.val(this._format(i)),void 0}("max"===e||"min"===e||"step"===e)&&"string"==typeof t&&(t=this._parse(t)),"icons"===e&&(this.buttons.first().find(".ui-icon").removeClass(this.options.icons.up).addClass(t.up),this.buttons.last().find(".ui-icon").removeClass(this.options.icons.down).addClass(t.down)),this._super(e,t),"disabled"===e&&(this.widget().toggleClass("ui-state-disabled",!!t),this.element.prop("disabled",!!t),this.buttons.button(t?"disable":"enable"))},_setOptions:h(function(e){this._super(e)}),_parse:function(e){return"string"==typeof e&&""!==e&&(e=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(e,10,this.options.culture):+e),""===e||isNaN(e)?null:e},_format:function(e){return""===e?"":window.Globalize&&this.options.numberFormat?Globalize.format(e,this.options.numberFormat,this.options.culture):e},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},isValid:function(){var e=this.value();return null===e?!1:e===this._adjustValue(e)},_value:function(e,t){var i;""!==e&&(i=this._parse(e),null!==i&&(t||(i=this._adjustValue(i)),e=this._format(i))),this.element.val(e),this._refresh()},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",!1).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:h(function(e){this._stepUp(e)}),_stepUp:function(e){this._start()&&(this._spin((e||1)*this.options.step),this._stop())},stepDown:h(function(e){this._stepDown(e)}),_stepDown:function(e){this._start()&&(this._spin((e||1)*-this.options.step),this._stop())},pageUp:h(function(e){this._stepUp((e||1)*this.options.page)}),pageDown:h(function(e){this._stepDown((e||1)*this.options.page)}),value:function(e){return arguments.length?(h(this._value).call(this,e),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}}),e.widget("ui.tabs",{version:"1.11.4",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_isLocal:function(){var e=/#.*$/;return function(t){var i,s;t=t.cloneNode(!1),i=t.href.replace(e,""),s=location.href.replace(e,"");try{i=decodeURIComponent(i)}catch(n){}try{s=decodeURIComponent(s)}catch(n){}return t.hash.length>1&&i===s}}(),_create:function(){var t=this,i=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",i.collapsible),this._processTabs(),i.active=this._initialActive(),e.isArray(i.disabled)&&(i.disabled=e.unique(i.disabled.concat(e.map(this.tabs.filter(".ui-state-disabled"),function(e){return t.tabs.index(e)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):e(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var t=this.options.active,i=this.options.collapsible,s=location.hash.substring(1);return null===t&&(s&&this.tabs.each(function(i,n){return e(n).attr("aria-controls")===s?(t=i,!1):void 0}),null===t&&(t=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===t||-1===t)&&(t=this.tabs.length?0:!1)),t!==!1&&(t=this.tabs.index(this.tabs.eq(t)),-1===t&&(t=i?!1:0)),!i&&t===!1&&this.anchors.length&&(t=0),t},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):e()}},_tabKeydown:function(t){var i=e(this.document[0].activeElement).closest("li"),s=this.tabs.index(i),n=!0;if(!this._handlePageNav(t)){switch(t.keyCode){case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:s++;break;case e.ui.keyCode.UP:case e.ui.keyCode.LEFT:n=!1,s--;break;case e.ui.keyCode.END:s=this.anchors.length-1;break;case e.ui.keyCode.HOME:s=0;break;case e.ui.keyCode.SPACE:return t.preventDefault(),clearTimeout(this.activating),this._activate(s),void 0;case e.ui.keyCode.ENTER:return t.preventDefault(),clearTimeout(this.activating),this._activate(s===this.options.active?!1:s),void 0;default:return}t.preventDefault(),clearTimeout(this.activating),s=this._focusNextTab(s,n),t.ctrlKey||t.metaKey||(i.attr("aria-selected","false"),this.tabs.eq(s).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",s)},this.delay))}},_panelKeydown:function(t){this._handlePageNav(t)||t.ctrlKey&&t.keyCode===e.ui.keyCode.UP&&(t.preventDefault(),this.active.focus())},_handlePageNav:function(t){return t.altKey&&t.keyCode===e.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):t.altKey&&t.keyCode===e.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(t,i){function s(){return t>n&&(t=0),0>t&&(t=n),t}for(var n=this.tabs.length-1;-1!==e.inArray(s(),this.options.disabled);)t=i?t+1:t-1;return t},_focusNextTab:function(e,t){return e=this._findNextTab(e,t),this.tabs.eq(e).focus(),e},_setOption:function(e,t){return"active"===e?(this._activate(t),void 0):"disabled"===e?(this._setupDisabled(t),void 0):(this._super(e,t),"collapsible"===e&&(this.element.toggleClass("ui-tabs-collapsible",t),t||this.options.active!==!1||this._activate(0)),"event"===e&&this._setupEvents(t),"heightStyle"===e&&this._setupHeightStyle(t),void 0)},_sanitizeSelector:function(e){return e?e.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var t=this.options,i=this.tablist.children(":has(a[href])");t.disabled=e.map(i.filter(".ui-state-disabled"),function(e){return i.index(e)}),this._processTabs(),t.active!==!1&&this.anchors.length?this.active.length&&!e.contains(this.tablist[0],this.active[0])?this.tabs.length===t.disabled.length?(t.active=!1,this.active=e()):this._activate(this._findNextTab(Math.max(0,t.active-1),!1)):t.active=this.tabs.index(this.active):(t.active=!1,this.active=e()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var t=this,i=this.tabs,s=this.anchors,n=this.panels;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist").delegate("> li","mousedown"+this.eventNamespace,function(t){e(this).is(".ui-state-disabled")&&t.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){e(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return e("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=e(),this.anchors.each(function(i,s){var n,a,o,r=e(s).uniqueId().attr("id"),h=e(s).closest("li"),l=h.attr("aria-controls");t._isLocal(s)?(n=s.hash,o=n.substring(1),a=t.element.find(t._sanitizeSelector(n))):(o=h.attr("aria-controls")||e({}).uniqueId()[0].id,n="#"+o,a=t.element.find(n),a.length||(a=t._createPanel(o),a.insertAfter(t.panels[i-1]||t.tablist)),a.attr("aria-live","polite")),a.length&&(t.panels=t.panels.add(a)),l&&h.data("ui-tabs-aria-controls",l),h.attr({"aria-controls":o,"aria-labelledby":r}),a.attr("aria-labelledby",r)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel"),i&&(this._off(i.not(this.tabs)),this._off(s.not(this.anchors)),this._off(n.not(this.panels)))},_getList:function(){return this.tablist||this.element.find("ol,ul").eq(0)},_createPanel:function(t){return e("<div>").attr("id",t).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(t){e.isArray(t)&&(t.length?t.length===this.anchors.length&&(t=!0):t=!1);for(var i,s=0;i=this.tabs[s];s++)t===!0||-1!==e.inArray(s,t)?e(i).addClass("ui-state-disabled").attr("aria-disabled","true"):e(i).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=t},_setupEvents:function(t){var i={};t&&e.each(t.split(" "),function(e,t){i[t]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(!0,this.anchors,{click:function(e){e.preventDefault()}}),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(t){var i,s=this.element.parent();"fill"===t?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var t=e(this),s=t.css("position");"absolute"!==s&&"fixed"!==s&&(i-=t.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=e(this).outerHeight(!0)}),this.panels.each(function(){e(this).height(Math.max(0,i-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):"auto"===t&&(i=0,this.panels.each(function(){i=Math.max(i,e(this).height("").height())}).height(i))},_eventHandler:function(t){var i=this.options,s=this.active,n=e(t.currentTarget),a=n.closest("li"),o=a[0]===s[0],r=o&&i.collapsible,h=r?e():this._getPanelForTab(a),l=s.length?this._getPanelForTab(s):e(),u={oldTab:s,oldPanel:l,newTab:r?e():a,newPanel:h};t.preventDefault(),a.hasClass("ui-state-disabled")||a.hasClass("ui-tabs-loading")||this.running||o&&!i.collapsible||this._trigger("beforeActivate",t,u)===!1||(i.active=r?!1:this.tabs.index(a),this.active=o?e():a,this.xhr&&this.xhr.abort(),l.length||h.length||e.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(a),t),this._toggle(t,u))},_toggle:function(t,i){function s(){a.running=!1,a._trigger("activate",t,i)}function n(){i.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),o.length&&a.options.show?a._show(o,a.options.show,s):(o.show(),s())}var a=this,o=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),n()}):(i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),r.hide(),n()),r.attr("aria-hidden","true"),i.oldTab.attr({"aria-selected":"false","aria-expanded":"false"}),o.length&&r.length?i.oldTab.attr("tabIndex",-1):o.length&&this.tabs.filter(function(){return 0===e(this).attr("tabIndex")}).attr("tabIndex",-1),o.attr("aria-hidden","false"),i.newTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_activate:function(t){var i,s=this._findActive(t);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:e.noop}))},_findActive:function(t){return t===!1?e():this.tabs.eq(t)},_getIndex:function(e){return"string"==typeof e&&(e=this.anchors.index(this.anchors.filter("[href$='"+e+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tablist.unbind(this.eventNamespace),this.tabs.add(this.panels).each(function(){e.data(this,"ui-tabs-destroy")?e(this).remove():e(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var t=e(this),i=t.data("ui-tabs-aria-controls");i?t.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):t.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(t){var i=this.options.disabled;i!==!1&&(void 0===t?i=!1:(t=this._getIndex(t),i=e.isArray(i)?e.map(i,function(e){return e!==t?e:null}):e.map(this.tabs,function(e,i){return i!==t?i:null})),this._setupDisabled(i))},disable:function(t){var i=this.options.disabled;if(i!==!0){if(void 0===t)i=!0;else{if(t=this._getIndex(t),-1!==e.inArray(t,i))return;i=e.isArray(i)?e.merge([t],i).sort():[t]}this._setupDisabled(i)}},load:function(t,i){t=this._getIndex(t);var s=this,n=this.tabs.eq(t),a=n.find(".ui-tabs-anchor"),o=this._getPanelForTab(n),r={tab:n,panel:o},h=function(e,t){"abort"===t&&s.panels.stop(!1,!0),n.removeClass("ui-tabs-loading"),o.removeAttr("aria-busy"),e===s.xhr&&delete s.xhr};this._isLocal(a[0])||(this.xhr=e.ajax(this._ajaxSettings(a,i,r)),this.xhr&&"canceled"!==this.xhr.statusText&&(n.addClass("ui-tabs-loading"),o.attr("aria-busy","true"),this.xhr.done(function(e,t,n){setTimeout(function(){o.html(e),s._trigger("load",i,r),h(n,t)},1)}).fail(function(e,t){setTimeout(function(){h(e,t)},1)})))},_ajaxSettings:function(t,i,s){var n=this;return{url:t.attr("href"),beforeSend:function(t,a){return n._trigger("beforeLoad",i,e.extend({jqXHR:t,ajaxSettings:a},s))}}},_getPanelForTab:function(t){var i=e(t).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}}),e.widget("ui.tooltip",{version:"1.11.4",options:{content:function(){var t=e(this).attr("title")||"";return e("<a>").text(t).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_addDescribedBy:function(t,i){var s=(t.attr("aria-describedby")||"").split(/\s+/);s.push(i),t.data("ui-tooltip-id",i).attr("aria-describedby",e.trim(s.join(" ")))},_removeDescribedBy:function(t){var i=t.data("ui-tooltip-id"),s=(t.attr("aria-describedby")||"").split(/\s+/),n=e.inArray(i,s);-1!==n&&s.splice(n,1),t.removeData("ui-tooltip-id"),s=e.trim(s.join(" ")),s?t.attr("aria-describedby",s):t.removeAttr("aria-describedby")},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable(),this.liveRegion=e("<div>").attr({role:"log","aria-live":"assertive","aria-relevant":"additions"}).addClass("ui-helper-hidden-accessible").appendTo(this.document[0].body)},_setOption:function(t,i){var s=this;return"disabled"===t?(this[i?"_disable":"_enable"](),this.options[t]=i,void 0):(this._super(t,i),"content"===t&&e.each(this.tooltips,function(e,t){s._updateContent(t.element)}),void 0)},_disable:function(){var t=this;e.each(this.tooltips,function(i,s){var n=e.Event("blur");n.target=n.currentTarget=s.element[0],t.close(n,!0)}),this.element.find(this.options.items).addBack().each(function(){var t=e(this);t.is("[title]")&&t.data("ui-tooltip-title",t.attr("title")).removeAttr("title")})},_enable:function(){this.element.find(this.options.items).addBack().each(function(){var t=e(this);t.data("ui-tooltip-title")&&t.attr("title",t.data("ui-tooltip-title"))})},open:function(t){var i=this,s=e(t?t.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),t&&"mouseover"===t.type&&s.parents().each(function(){var t,s=e(this);s.data("ui-tooltip-open")&&(t=e.Event("blur"),t.target=t.currentTarget=this,i.close(t,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._registerCloseHandlers(t,s),this._updateContent(s,t))},_updateContent:function(e,t){var i,s=this.options.content,n=this,a=t?t.type:null;return"string"==typeof s?this._open(t,e,s):(i=s.call(e[0],function(i){n._delay(function(){e.data("ui-tooltip-open")&&(t&&(t.type=a),this._open(t,e,i))})}),i&&this._open(t,e,i),void 0)},_open:function(t,i,s){function n(e){l.of=e,o.is(":hidden")||o.position(l)}var a,o,r,h,l=e.extend({},this.options.position);if(s){if(a=this._find(i))return a.tooltip.find(".ui-tooltip-content").html(s),void 0;i.is("[title]")&&(t&&"mouseover"===t.type?i.attr("title",""):i.removeAttr("title")),a=this._tooltip(i),o=a.tooltip,this._addDescribedBy(i,o.attr("id")),o.find(".ui-tooltip-content").html(s),this.liveRegion.children().hide(),s.clone?(h=s.clone(),h.removeAttr("id").find("[id]").removeAttr("id")):h=s,e("<div>").html(h).appendTo(this.liveRegion),this.options.track&&t&&/^mouse/.test(t.type)?(this._on(this.document,{mousemove:n}),n(t)):o.position(e.extend({of:i},this.options.position)),o.hide(),this._show(o,this.options.show),this.options.show&&this.options.show.delay&&(r=this.delayedShow=setInterval(function(){o.is(":visible")&&(n(l.of),clearInterval(r))},e.fx.interval)),this._trigger("open",t,{tooltip:o})}},_registerCloseHandlers:function(t,i){var s={keyup:function(t){if(t.keyCode===e.ui.keyCode.ESCAPE){var s=e.Event(t);s.currentTarget=i[0],this.close(s,!0)}}};i[0]!==this.element[0]&&(s.remove=function(){this._removeTooltip(this._find(i).tooltip)}),t&&"mouseover"!==t.type||(s.mouseleave="close"),t&&"focusin"!==t.type||(s.focusout="close"),this._on(!0,i,s)},close:function(t){var i,s=this,n=e(t?t.currentTarget:this.element),a=this._find(n);return a?(i=a.tooltip,a.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&!n.attr("title")&&n.attr("title",n.data("ui-tooltip-title")),this._removeDescribedBy(n),a.hiding=!0,i.stop(!0),this._hide(i,this.options.hide,function(){s._removeTooltip(e(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),t&&"mouseleave"===t.type&&e.each(this.parents,function(t,i){e(i.element).attr("title",i.title),delete s.parents[t]}),a.closing=!0,this._trigger("close",t,{tooltip:i}),a.hiding||(a.closing=!1)),void 0):(n.removeData("ui-tooltip-open"),void 0)},_tooltip:function(t){var i=e("<div>").attr("role","tooltip").addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||"")),s=i.uniqueId().attr("id");return e("<div>").addClass("ui-tooltip-content").appendTo(i),i.appendTo(this.document[0].body),this.tooltips[s]={element:t,tooltip:i}},_find:function(e){var t=e.data("ui-tooltip-id");return t?this.tooltips[t]:null},_removeTooltip:function(e){e.remove(),delete this.tooltips[e.attr("id")]},_destroy:function(){var t=this;e.each(this.tooltips,function(i,s){var n=e.Event("blur"),a=s.element;n.target=n.currentTarget=a[0],t.close(n,!0),e("#"+i).remove(),a.data("ui-tooltip-title")&&(a.attr("title")||a.attr("title",a.data("ui-tooltip-title")),a.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}});var y="ui-effects-",b=e;e.effects={effect:{}},function(e,t){function i(e,t,i){var s=d[t.type]||{};return null==e?i||!t.def?null:t.def:(e=s.floor?~~e:parseFloat(e),isNaN(e)?t.def:s.mod?(e+s.mod)%s.mod:0>e?0:e>s.max?s.max:e)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(e,a){var o,r=a.re.exec(i),h=r&&a.parse(r),l=a.space||"rgba";return h?(o=s[l](h),s[u[l].cache]=o[u[l].cache],n=s._rgba=o._rgba,!1):t}),n.length?("0,0,0,0"===n.join()&&e.extend(n,a.transparent),s):a[i]}function n(e,t,i){return i=(i+1)%1,1>6*i?e+6*(t-e)*i:1>2*i?t:2>3*i?e+6*(t-e)*(2/3-i):e}var a,o="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(e){return[e[1],e[2],e[3],e[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(e){return[2.55*e[1],2.55*e[2],2.55*e[3],e[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(e){return[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(e){return[parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(e){return[e[1],e[2]/100,e[3]/100,e[4]]}}],l=e.Color=function(t,i,s,n){return new e.Color.fn.parse(t,i,s,n)},u={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},d={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},c=l.support={},p=e("<p>")[0],f=e.each;p.style.cssText="background-color:rgba(1,1,1,.5)",c.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(u,function(e,t){t.cache="_"+e,t.props.alpha={idx:3,type:"percent",def:1}}),l.fn=e.extend(l.prototype,{parse:function(n,o,r,h){if(n===t)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=e(n).css(o),o=t);var d=this,c=e.type(n),p=this._rgba=[];return o!==t&&(n=[n,o,r,h],c="array"),"string"===c?this.parse(s(n)||a._default):"array"===c?(f(u.rgba.props,function(e,t){p[t.idx]=i(n[t.idx],t)}),this):"object"===c?(n instanceof l?f(u,function(e,t){n[t.cache]&&(d[t.cache]=n[t.cache].slice())}):f(u,function(t,s){var a=s.cache;f(s.props,function(e,t){if(!d[a]&&s.to){if("alpha"===e||null==n[e])return;d[a]=s.to(d._rgba)}d[a][t.idx]=i(n[e],t,!0)}),d[a]&&0>e.inArray(null,d[a].slice(0,3))&&(d[a][3]=1,s.from&&(d._rgba=s.from(d[a])))}),this):t},is:function(e){var i=l(e),s=!0,n=this;return f(u,function(e,a){var o,r=i[a.cache];return r&&(o=n[a.cache]||a.to&&a.to(n._rgba)||[],f(a.props,function(e,i){return null!=r[i.idx]?s=r[i.idx]===o[i.idx]:t})),s}),s},_space:function(){var e=[],t=this;return f(u,function(i,s){t[s.cache]&&e.push(i)}),e.pop()},transition:function(e,t){var s=l(e),n=s._space(),a=u[n],o=0===this.alpha()?l("transparent"):this,r=o[a.cache]||a.to(o._rgba),h=r.slice();return s=s[a.cache],f(a.props,function(e,n){var a=n.idx,o=r[a],l=s[a],u=d[n.type]||{};null!==l&&(null===o?h[a]=l:(u.mod&&(l-o>u.mod/2?o+=u.mod:o-l>u.mod/2&&(o-=u.mod)),h[a]=i((l-o)*t+o,n)))}),this[n](h)},blend:function(t){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(t)._rgba;return l(e.map(i,function(e,t){return(1-s)*n[t]+s*e}))},toRgbaString:function(){var t="rgba(",i=e.map(this._rgba,function(e,t){return null==e?t>2?1:0:e});return 1===i[3]&&(i.pop(),t="rgb("),t+i.join()+")"},toHslaString:function(){var t="hsla(",i=e.map(this.hsla(),function(e,t){return null==e&&(e=t>2?1:0),t&&3>t&&(e=Math.round(100*e)+"%"),e});return 1===i[3]&&(i.pop(),t="hsl("),t+i.join()+")"},toHexString:function(t){var i=this._rgba.slice(),s=i.pop();return t&&i.push(~~(255*s)),"#"+e.map(i,function(e){return e=(e||0).toString(16),1===e.length?"0"+e:e}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,u.hsla.to=function(e){if(null==e[0]||null==e[1]||null==e[2])return[null,null,null,e[3]];var t,i,s=e[0]/255,n=e[1]/255,a=e[2]/255,o=e[3],r=Math.max(s,n,a),h=Math.min(s,n,a),l=r-h,u=r+h,d=.5*u;return t=h===r?0:s===r?60*(n-a)/l+360:n===r?60*(a-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=d?l/u:l/(2-u),[Math.round(t)%360,i,d,null==o?1:o]},u.hsla.from=function(e){if(null==e[0]||null==e[1]||null==e[2])return[null,null,null,e[3]];var t=e[0]/360,i=e[1],s=e[2],a=e[3],o=.5>=s?s*(1+i):s+i-s*i,r=2*s-o;return[Math.round(255*n(r,o,t+1/3)),Math.round(255*n(r,o,t)),Math.round(255*n(r,o,t-1/3)),a]},f(u,function(s,n){var a=n.props,o=n.cache,h=n.to,u=n.from;l.fn[s]=function(s){if(h&&!this[o]&&(this[o]=h(this._rgba)),s===t)return this[o].slice();var n,r=e.type(s),d="array"===r||"object"===r?s:arguments,c=this[o].slice();return f(a,function(e,t){var s=d["object"===r?e:t.idx];null==s&&(s=c[t.idx]),c[t.idx]=i(s,t)}),u?(n=l(u(c)),n[o]=c,n):l(c)},f(a,function(t,i){l.fn[t]||(l.fn[t]=function(n){var a,o=e.type(n),h="alpha"===t?this._hsla?"hsla":"rgba":s,l=this[h](),u=l[i.idx];return"undefined"===o?u:("function"===o&&(n=n.call(this,u),o=e.type(n)),null==n&&i.empty?this:("string"===o&&(a=r.exec(n),a&&(n=u+parseFloat(a[2])*("+"===a[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(t){var i=t.split(" ");f(i,function(t,i){e.cssHooks[i]={set:function(t,n){var a,o,r="";if("transparent"!==n&&("string"!==e.type(n)||(a=s(n)))){if(n=l(a||n),!c.rgba&&1!==n._rgba[3]){for(o="backgroundColor"===i?t.parentNode:t;(""===r||"transparent"===r)&&o&&o.style;)try{r=e.css(o,"backgroundColor"),o=o.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{t.style[i]=n}catch(h){}}},e.fx.step[i]=function(t){t.colorInit||(t.start=l(t.elem,i),t.end=l(t.end),t.colorInit=!0),e.cssHooks[i].set(t.elem,t.start.transition(t.end,t.pos))}})},l.hook(o),e.cssHooks.borderColor={expand:function(e){var t={};return f(["Top","Right","Bottom","Left"],function(i,s){t["border"+s+"Color"]=e}),t}},a=e.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(b),function(){function t(t){var i,s,n=t.ownerDocument.defaultView?t.ownerDocument.defaultView.getComputedStyle(t,null):t.currentStyle,a={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(a[e.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(a[i]=n[i]);return a}function i(t,i){var s,a,o={};for(s in i)a=i[s],t[s]!==a&&(n[s]||(e.fx.step[s]||!isNaN(parseFloat(a)))&&(o[s]=a));return o}var s=["add","remove","toggle"],n={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};e.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(t,i){e.fx.step[i]=function(e){("none"!==e.end&&!e.setAttr||1===e.pos&&!e.setAttr)&&(b.style(e.elem,i,e.end),e.setAttr=!0)}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e.effects.animateClass=function(n,a,o,r){var h=e.speed(a,o,r);return this.queue(function(){var a,o=e(this),r=o.attr("class")||"",l=h.children?o.find("*").addBack():o;l=l.map(function(){var i=e(this);return{el:i,start:t(this)}}),a=function(){e.each(s,function(e,t){n[t]&&o[t+"Class"](n[t])})},a(),l=l.map(function(){return this.end=t(this.el[0]),this.diff=i(this.start,this.end),this}),o.attr("class",r),l=l.map(function(){var t=this,i=e.Deferred(),s=e.extend({},h,{queue:!1,complete:function(){i.resolve(t)}});return this.el.animate(this.diff,s),i.promise()}),e.when.apply(e,l.get()).done(function(){a(),e.each(arguments,function(){var t=this.el;e.each(this.diff,function(e){t.css(e,"")})}),h.complete.call(o[0])})})},e.fn.extend({addClass:function(t){return function(i,s,n,a){return s?e.effects.animateClass.call(this,{add:i},s,n,a):t.apply(this,arguments)}}(e.fn.addClass),removeClass:function(t){return function(i,s,n,a){return arguments.length>1?e.effects.animateClass.call(this,{remove:i},s,n,a):t.apply(this,arguments)}}(e.fn.removeClass),toggleClass:function(t){return function(i,s,n,a,o){return"boolean"==typeof s||void 0===s?n?e.effects.animateClass.call(this,s?{add:i}:{remove:i},n,a,o):t.apply(this,arguments):e.effects.animateClass.call(this,{toggle:i},s,n,a)}}(e.fn.toggleClass),switchClass:function(t,i,s,n,a){return e.effects.animateClass.call(this,{add:i,remove:t},s,n,a)}})}(),function(){function t(t,i,s,n){return e.isPlainObject(t)&&(i=t,t=t.effect),t={effect:t},null==i&&(i={}),e.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||e.fx.speeds[i])&&(n=s,s=i,i={}),e.isFunction(s)&&(n=s,s=null),i&&e.extend(t,i),s=s||i.duration,t.duration=e.fx.off?0:"number"==typeof s?s:s in e.fx.speeds?e.fx.speeds[s]:e.fx.speeds._default,t.complete=n||i.complete,t}function i(t){return!t||"number"==typeof t||e.fx.speeds[t]?!0:"string"!=typeof t||e.effects.effect[t]?e.isFunction(t)?!0:"object"!=typeof t||t.effect?!1:!0:!0}e.extend(e.effects,{version:"1.11.4",save:function(e,t){for(var i=0;t.length>i;i++)null!==t[i]&&e.data(y+t[i],e[0].style[t[i]])},restore:function(e,t){var i,s;for(s=0;t.length>s;s++)null!==t[s]&&(i=e.data(y+t[s]),void 0===i&&(i=""),e.css(t[s],i))},setMode:function(e,t){return"toggle"===t&&(t=e.is(":hidden")?"show":"hide"),t},getBaseline:function(e,t){var i,s;switch(e[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=e[0]/t.height}switch(e[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=e[1]/t.width}return{x:s,y:i}},createWrapper:function(t){if(t.parent().is(".ui-effects-wrapper"))return t.parent();var i={width:t.outerWidth(!0),height:t.outerHeight(!0),"float":t.css("float")},s=e("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:t.width(),height:t.height()},a=document.activeElement;try{a.id}catch(o){a=document.body}return t.wrap(s),(t[0]===a||e.contains(t[0],a))&&e(a).focus(),s=t.parent(),"static"===t.css("position")?(s.css({position:"relative"}),t.css({position:"relative"})):(e.extend(i,{position:t.css("position"),zIndex:t.css("z-index")}),e.each(["top","left","bottom","right"],function(e,s){i[s]=t.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),t.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),t.css(n),s.css(i).show()},removeWrapper:function(t){var i=document.activeElement;
+return t.parent().is(".ui-effects-wrapper")&&(t.parent().replaceWith(t),(t[0]===i||e.contains(t[0],i))&&e(i).focus()),t},setTransition:function(t,i,s,n){return n=n||{},e.each(i,function(e,i){var a=t.cssUnit(i);a[0]>0&&(n[i]=a[0]*s+a[1])}),n}}),e.fn.extend({effect:function(){function i(t){function i(){e.isFunction(a)&&a.call(n[0]),e.isFunction(t)&&t()}var n=e(this),a=s.complete,r=s.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),i()):o.call(n[0],s,i)}var s=t.apply(this,arguments),n=s.mode,a=s.queue,o=e.effects.effect[s.effect];return e.fx.off||!o?n?this[n](s.duration,s.complete):this.each(function(){s.complete&&s.complete.call(this)}):a===!1?this.each(i):this.queue(a||"fx",i)},show:function(e){return function(s){if(i(s))return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="show",this.effect.call(this,n)}}(e.fn.show),hide:function(e){return function(s){if(i(s))return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="hide",this.effect.call(this,n)}}(e.fn.hide),toggle:function(e){return function(s){if(i(s)||"boolean"==typeof s)return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="toggle",this.effect.call(this,n)}}(e.fn.toggle),cssUnit:function(t){var i=this.css(t),s=[];return e.each(["em","px","%","pt"],function(e,t){i.indexOf(t)>0&&(s=[parseFloat(i),t])}),s}})}(),function(){var t={};e.each(["Quad","Cubic","Quart","Quint","Expo"],function(e,i){t[i]=function(t){return Math.pow(t,e+2)}}),e.extend(t,{Sine:function(e){return 1-Math.cos(e*Math.PI/2)},Circ:function(e){return 1-Math.sqrt(1-e*e)},Elastic:function(e){return 0===e||1===e?e:-Math.pow(2,8*(e-1))*Math.sin((80*(e-1)-7.5)*Math.PI/15)},Back:function(e){return e*e*(3*e-2)},Bounce:function(e){for(var t,i=4;((t=Math.pow(2,--i))-1)/11>e;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*t-2)/22-e,2)}}),e.each(t,function(t,i){e.easing["easeIn"+t]=i,e.easing["easeOut"+t]=function(e){return 1-i(1-e)},e.easing["easeInOut"+t]=function(e){return.5>e?i(2*e)/2:1-i(-2*e+2)/2}})}(),e.effects,e.effects.effect.blind=function(t,i){var s,n,a,o=e(this),r=/up|down|vertical/,h=/up|left|vertical|horizontal/,l=["position","top","bottom","left","right","height","width"],u=e.effects.setMode(o,t.mode||"hide"),d=t.direction||"up",c=r.test(d),p=c?"height":"width",f=c?"top":"left",m=h.test(d),g={},v="show"===u;o.parent().is(".ui-effects-wrapper")?e.effects.save(o.parent(),l):e.effects.save(o,l),o.show(),s=e.effects.createWrapper(o).css({overflow:"hidden"}),n=s[p](),a=parseFloat(s.css(f))||0,g[p]=v?n:0,m||(o.css(c?"bottom":"right",0).css(c?"top":"left","auto").css({position:"absolute"}),g[f]=v?a:n+a),v&&(s.css(p,0),m||s.css(f,a+n)),s.animate(g,{duration:t.duration,easing:t.easing,queue:!1,complete:function(){"hide"===u&&o.hide(),e.effects.restore(o,l),e.effects.removeWrapper(o),i()}})},e.effects.effect.bounce=function(t,i){var s,n,a,o=e(this),r=["position","top","bottom","left","right","height","width"],h=e.effects.setMode(o,t.mode||"effect"),l="hide"===h,u="show"===h,d=t.direction||"up",c=t.distance,p=t.times||5,f=2*p+(u||l?1:0),m=t.duration/f,g=t.easing,v="up"===d||"down"===d?"top":"left",y="up"===d||"left"===d,b=o.queue(),_=b.length;for((u||l)&&r.push("opacity"),e.effects.save(o,r),o.show(),e.effects.createWrapper(o),c||(c=o["top"===v?"outerHeight":"outerWidth"]()/3),u&&(a={opacity:1},a[v]=0,o.css("opacity",0).css(v,y?2*-c:2*c).animate(a,m,g)),l&&(c/=Math.pow(2,p-1)),a={},a[v]=0,s=0;p>s;s++)n={},n[v]=(y?"-=":"+=")+c,o.animate(n,m,g).animate(a,m,g),c=l?2*c:c/2;l&&(n={opacity:0},n[v]=(y?"-=":"+=")+c,o.animate(n,m,g)),o.queue(function(){l&&o.hide(),e.effects.restore(o,r),e.effects.removeWrapper(o),i()}),_>1&&b.splice.apply(b,[1,0].concat(b.splice(_,f+1))),o.dequeue()},e.effects.effect.clip=function(t,i){var s,n,a,o=e(this),r=["position","top","bottom","left","right","height","width"],h=e.effects.setMode(o,t.mode||"hide"),l="show"===h,u=t.direction||"vertical",d="vertical"===u,c=d?"height":"width",p=d?"top":"left",f={};e.effects.save(o,r),o.show(),s=e.effects.createWrapper(o).css({overflow:"hidden"}),n="IMG"===o[0].tagName?s:o,a=n[c](),l&&(n.css(c,0),n.css(p,a/2)),f[c]=l?a:0,f[p]=l?0:a/2,n.animate(f,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){l||o.hide(),e.effects.restore(o,r),e.effects.removeWrapper(o),i()}})},e.effects.effect.drop=function(t,i){var s,n=e(this),a=["position","top","bottom","left","right","opacity","height","width"],o=e.effects.setMode(n,t.mode||"hide"),r="show"===o,h=t.direction||"left",l="up"===h||"down"===h?"top":"left",u="up"===h||"left"===h?"pos":"neg",d={opacity:r?1:0};e.effects.save(n,a),n.show(),e.effects.createWrapper(n),s=t.distance||n["top"===l?"outerHeight":"outerWidth"](!0)/2,r&&n.css("opacity",0).css(l,"pos"===u?-s:s),d[l]=(r?"pos"===u?"+=":"-=":"pos"===u?"-=":"+=")+s,n.animate(d,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){"hide"===o&&n.hide(),e.effects.restore(n,a),e.effects.removeWrapper(n),i()}})},e.effects.effect.explode=function(t,i){function s(){b.push(this),b.length===d*c&&n()}function n(){p.css({visibility:"visible"}),e(b).remove(),m||p.hide(),i()}var a,o,r,h,l,u,d=t.pieces?Math.round(Math.sqrt(t.pieces)):3,c=d,p=e(this),f=e.effects.setMode(p,t.mode||"hide"),m="show"===f,g=p.show().css("visibility","hidden").offset(),v=Math.ceil(p.outerWidth()/c),y=Math.ceil(p.outerHeight()/d),b=[];for(a=0;d>a;a++)for(h=g.top+a*y,u=a-(d-1)/2,o=0;c>o;o++)r=g.left+o*v,l=o-(c-1)/2,p.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-o*v,top:-a*y}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:v,height:y,left:r+(m?l*v:0),top:h+(m?u*y:0),opacity:m?0:1}).animate({left:r+(m?0:l*v),top:h+(m?0:u*y),opacity:m?1:0},t.duration||500,t.easing,s)},e.effects.effect.fade=function(t,i){var s=e(this),n=e.effects.setMode(s,t.mode||"toggle");s.animate({opacity:n},{queue:!1,duration:t.duration,easing:t.easing,complete:i})},e.effects.effect.fold=function(t,i){var s,n,a=e(this),o=["position","top","bottom","left","right","height","width"],r=e.effects.setMode(a,t.mode||"hide"),h="show"===r,l="hide"===r,u=t.size||15,d=/([0-9]+)%/.exec(u),c=!!t.horizFirst,p=h!==c,f=p?["width","height"]:["height","width"],m=t.duration/2,g={},v={};e.effects.save(a,o),a.show(),s=e.effects.createWrapper(a).css({overflow:"hidden"}),n=p?[s.width(),s.height()]:[s.height(),s.width()],d&&(u=parseInt(d[1],10)/100*n[l?0:1]),h&&s.css(c?{height:0,width:u}:{height:u,width:0}),g[f[0]]=h?n[0]:u,v[f[1]]=h?n[1]:0,s.animate(g,m,t.easing).animate(v,m,t.easing,function(){l&&a.hide(),e.effects.restore(a,o),e.effects.removeWrapper(a),i()})},e.effects.effect.highlight=function(t,i){var s=e(this),n=["backgroundImage","backgroundColor","opacity"],a=e.effects.setMode(s,t.mode||"show"),o={backgroundColor:s.css("backgroundColor")};"hide"===a&&(o.opacity=0),e.effects.save(s,n),s.show().css({backgroundImage:"none",backgroundColor:t.color||"#ffff99"}).animate(o,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){"hide"===a&&s.hide(),e.effects.restore(s,n),i()}})},e.effects.effect.size=function(t,i){var s,n,a,o=e(this),r=["position","top","bottom","left","right","width","height","overflow","opacity"],h=["position","top","bottom","left","right","overflow","opacity"],l=["width","height","overflow"],u=["fontSize"],d=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],c=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=e.effects.setMode(o,t.mode||"effect"),f=t.restore||"effect"!==p,m=t.scale||"both",g=t.origin||["middle","center"],v=o.css("position"),y=f?r:h,b={height:0,width:0,outerHeight:0,outerWidth:0};"show"===p&&o.show(),s={height:o.height(),width:o.width(),outerHeight:o.outerHeight(),outerWidth:o.outerWidth()},"toggle"===t.mode&&"show"===p?(o.from=t.to||b,o.to=t.from||s):(o.from=t.from||("show"===p?b:s),o.to=t.to||("hide"===p?b:s)),a={from:{y:o.from.height/s.height,x:o.from.width/s.width},to:{y:o.to.height/s.height,x:o.to.width/s.width}},("box"===m||"both"===m)&&(a.from.y!==a.to.y&&(y=y.concat(d),o.from=e.effects.setTransition(o,d,a.from.y,o.from),o.to=e.effects.setTransition(o,d,a.to.y,o.to)),a.from.x!==a.to.x&&(y=y.concat(c),o.from=e.effects.setTransition(o,c,a.from.x,o.from),o.to=e.effects.setTransition(o,c,a.to.x,o.to))),("content"===m||"both"===m)&&a.from.y!==a.to.y&&(y=y.concat(u).concat(l),o.from=e.effects.setTransition(o,u,a.from.y,o.from),o.to=e.effects.setTransition(o,u,a.to.y,o.to)),e.effects.save(o,y),o.show(),e.effects.createWrapper(o),o.css("overflow","hidden").css(o.from),g&&(n=e.effects.getBaseline(g,s),o.from.top=(s.outerHeight-o.outerHeight())*n.y,o.from.left=(s.outerWidth-o.outerWidth())*n.x,o.to.top=(s.outerHeight-o.to.outerHeight)*n.y,o.to.left=(s.outerWidth-o.to.outerWidth)*n.x),o.css(o.from),("content"===m||"both"===m)&&(d=d.concat(["marginTop","marginBottom"]).concat(u),c=c.concat(["marginLeft","marginRight"]),l=r.concat(d).concat(c),o.find("*[width]").each(function(){var i=e(this),s={height:i.height(),width:i.width(),outerHeight:i.outerHeight(),outerWidth:i.outerWidth()};f&&e.effects.save(i,l),i.from={height:s.height*a.from.y,width:s.width*a.from.x,outerHeight:s.outerHeight*a.from.y,outerWidth:s.outerWidth*a.from.x},i.to={height:s.height*a.to.y,width:s.width*a.to.x,outerHeight:s.height*a.to.y,outerWidth:s.width*a.to.x},a.from.y!==a.to.y&&(i.from=e.effects.setTransition(i,d,a.from.y,i.from),i.to=e.effects.setTransition(i,d,a.to.y,i.to)),a.from.x!==a.to.x&&(i.from=e.effects.setTransition(i,c,a.from.x,i.from),i.to=e.effects.setTransition(i,c,a.to.x,i.to)),i.css(i.from),i.animate(i.to,t.duration,t.easing,function(){f&&e.effects.restore(i,l)})})),o.animate(o.to,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){0===o.to.opacity&&o.css("opacity",o.from.opacity),"hide"===p&&o.hide(),e.effects.restore(o,y),f||("static"===v?o.css({position:"relative",top:o.to.top,left:o.to.left}):e.each(["top","left"],function(e,t){o.css(t,function(t,i){var s=parseInt(i,10),n=e?o.to.left:o.to.top;return"auto"===i?n+"px":s+n+"px"})})),e.effects.removeWrapper(o),i()}})},e.effects.effect.scale=function(t,i){var s=e(this),n=e.extend(!0,{},t),a=e.effects.setMode(s,t.mode||"effect"),o=parseInt(t.percent,10)||(0===parseInt(t.percent,10)?0:"hide"===a?0:100),r=t.direction||"both",h=t.origin,l={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()},u={y:"horizontal"!==r?o/100:1,x:"vertical"!==r?o/100:1};n.effect="size",n.queue=!1,n.complete=i,"effect"!==a&&(n.origin=h||["middle","center"],n.restore=!0),n.from=t.from||("show"===a?{height:0,width:0,outerHeight:0,outerWidth:0}:l),n.to={height:l.height*u.y,width:l.width*u.x,outerHeight:l.outerHeight*u.y,outerWidth:l.outerWidth*u.x},n.fade&&("show"===a&&(n.from.opacity=0,n.to.opacity=1),"hide"===a&&(n.from.opacity=1,n.to.opacity=0)),s.effect(n)},e.effects.effect.puff=function(t,i){var s=e(this),n=e.effects.setMode(s,t.mode||"hide"),a="hide"===n,o=parseInt(t.percent,10)||150,r=o/100,h={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()};e.extend(t,{effect:"scale",queue:!1,fade:!0,mode:n,complete:i,percent:a?o:100,from:a?h:{height:h.height*r,width:h.width*r,outerHeight:h.outerHeight*r,outerWidth:h.outerWidth*r}}),s.effect(t)},e.effects.effect.pulsate=function(t,i){var s,n=e(this),a=e.effects.setMode(n,t.mode||"show"),o="show"===a,r="hide"===a,h=o||"hide"===a,l=2*(t.times||5)+(h?1:0),u=t.duration/l,d=0,c=n.queue(),p=c.length;for((o||!n.is(":visible"))&&(n.css("opacity",0).show(),d=1),s=1;l>s;s++)n.animate({opacity:d},u,t.easing),d=1-d;n.animate({opacity:d},u,t.easing),n.queue(function(){r&&n.hide(),i()}),p>1&&c.splice.apply(c,[1,0].concat(c.splice(p,l+1))),n.dequeue()},e.effects.effect.shake=function(t,i){var s,n=e(this),a=["position","top","bottom","left","right","height","width"],o=e.effects.setMode(n,t.mode||"effect"),r=t.direction||"left",h=t.distance||20,l=t.times||3,u=2*l+1,d=Math.round(t.duration/u),c="up"===r||"down"===r?"top":"left",p="up"===r||"left"===r,f={},m={},g={},v=n.queue(),y=v.length;for(e.effects.save(n,a),n.show(),e.effects.createWrapper(n),f[c]=(p?"-=":"+=")+h,m[c]=(p?"+=":"-=")+2*h,g[c]=(p?"-=":"+=")+2*h,n.animate(f,d,t.easing),s=1;l>s;s++)n.animate(m,d,t.easing).animate(g,d,t.easing);n.animate(m,d,t.easing).animate(f,d/2,t.easing).queue(function(){"hide"===o&&n.hide(),e.effects.restore(n,a),e.effects.removeWrapper(n),i()}),y>1&&v.splice.apply(v,[1,0].concat(v.splice(y,u+1))),n.dequeue()},e.effects.effect.slide=function(t,i){var s,n=e(this),a=["position","top","bottom","left","right","width","height"],o=e.effects.setMode(n,t.mode||"show"),r="show"===o,h=t.direction||"left",l="up"===h||"down"===h?"top":"left",u="up"===h||"left"===h,d={};e.effects.save(n,a),n.show(),s=t.distance||n["top"===l?"outerHeight":"outerWidth"](!0),e.effects.createWrapper(n).css({overflow:"hidden"}),r&&n.css(l,u?isNaN(s)?"-"+s:-s:s),d[l]=(r?u?"+=":"-=":u?"-=":"+=")+s,n.animate(d,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){"hide"===o&&n.hide(),e.effects.restore(n,a),e.effects.removeWrapper(n),i()}})},e.effects.effect.transfer=function(t,i){var s=e(this),n=e(t.to),a="fixed"===n.css("position"),o=e("body"),r=a?o.scrollTop():0,h=a?o.scrollLeft():0,l=n.offset(),u={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},d=s.offset(),c=e("<div class='ui-effects-transfer'></div>").appendTo(document.body).addClass(t.className).css({top:d.top-r,left:d.left-h,height:s.innerHeight(),width:s.innerWidth(),position:a?"fixed":"absolute"}).animate(u,t.duration,t.easing,function(){c.remove(),i()})}});
\ No newline at end of file
diff --git a/htdocs/Libs/JQueryUI/jquery-ui.structure.css b/htdocs/Libs/JQueryUI/jquery-ui.structure.css
new file mode 100644
index 0000000..8184e15
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/jquery-ui.structure.css
@@ -0,0 +1,833 @@
+/*!
+ * jQuery UI CSS Framework 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/theming/
+ */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden {
+	display: none;
+}
+.ui-helper-hidden-accessible {
+	border: 0;
+	clip: rect(0 0 0 0);
+	height: 1px;
+	margin: -1px;
+	overflow: hidden;
+	padding: 0;
+	position: absolute;
+	width: 1px;
+}
+.ui-helper-reset {
+	margin: 0;
+	padding: 0;
+	border: 0;
+	outline: 0;
+	line-height: 1.3;
+	text-decoration: none;
+	font-size: 100%;
+	list-style: none;
+}
+.ui-helper-clearfix:before,
+.ui-helper-clearfix:after {
+	content: "";
+	display: table;
+	border-collapse: collapse;
+}
+.ui-helper-clearfix:after {
+	clear: both;
+}
+.ui-helper-clearfix {
+	min-height: 0; /* support: IE7 */
+}
+.ui-helper-zfix {
+	width: 100%;
+	height: 100%;
+	top: 0;
+	left: 0;
+	position: absolute;
+	opacity: 0;
+	filter:Alpha(Opacity=0); /* support: IE8 */
+}
+
+.ui-front {
+	z-index: 100;
+}
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled {
+	cursor: default !important;
+}
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+	display: block;
+	text-indent: -99999px;
+	overflow: hidden;
+	background-repeat: no-repeat;
+}
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay {
+	position: fixed;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+}
+.ui-draggable-handle {
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-resizable {
+	position: relative;
+}
+.ui-resizable-handle {
+	position: absolute;
+	font-size: 0.1px;
+	display: block;
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-resizable-disabled .ui-resizable-handle,
+.ui-resizable-autohide .ui-resizable-handle {
+	display: none;
+}
+.ui-resizable-n {
+	cursor: n-resize;
+	height: 7px;
+	width: 100%;
+	top: -5px;
+	left: 0;
+}
+.ui-resizable-s {
+	cursor: s-resize;
+	height: 7px;
+	width: 100%;
+	bottom: -5px;
+	left: 0;
+}
+.ui-resizable-e {
+	cursor: e-resize;
+	width: 7px;
+	right: -5px;
+	top: 0;
+	height: 100%;
+}
+.ui-resizable-w {
+	cursor: w-resize;
+	width: 7px;
+	left: -5px;
+	top: 0;
+	height: 100%;
+}
+.ui-resizable-se {
+	cursor: se-resize;
+	width: 12px;
+	height: 12px;
+	right: 1px;
+	bottom: 1px;
+}
+.ui-resizable-sw {
+	cursor: sw-resize;
+	width: 9px;
+	height: 9px;
+	left: -5px;
+	bottom: -5px;
+}
+.ui-resizable-nw {
+	cursor: nw-resize;
+	width: 9px;
+	height: 9px;
+	left: -5px;
+	top: -5px;
+}
+.ui-resizable-ne {
+	cursor: ne-resize;
+	width: 9px;
+	height: 9px;
+	right: -5px;
+	top: -5px;
+}
+.ui-selectable {
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-selectable-helper {
+	position: absolute;
+	z-index: 100;
+	border: 1px dotted black;
+}
+.ui-sortable-handle {
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-accordion .ui-accordion-header {
+	display: block;
+	cursor: pointer;
+	position: relative;
+	margin: 2px 0 0 0;
+	padding: .5em .5em .5em .7em;
+	min-height: 0; /* support: IE7 */
+	font-size: 100%;
+}
+.ui-accordion .ui-accordion-icons {
+	padding-left: 2.2em;
+}
+.ui-accordion .ui-accordion-icons .ui-accordion-icons {
+	padding-left: 2.2em;
+}
+.ui-accordion .ui-accordion-header .ui-accordion-header-icon {
+	position: absolute;
+	left: .5em;
+	top: 50%;
+	margin-top: -8px;
+}
+.ui-accordion .ui-accordion-content {
+	padding: 1em 2.2em;
+	border-top: 0;
+	overflow: auto;
+}
+.ui-autocomplete {
+	position: absolute;
+	top: 0;
+	left: 0;
+	cursor: default;
+}
+.ui-button {
+	display: inline-block;
+	position: relative;
+	padding: 0;
+	line-height: normal;
+	margin-right: .1em;
+	cursor: pointer;
+	vertical-align: middle;
+	text-align: center;
+	overflow: visible; /* removes extra width in IE */
+}
+.ui-button,
+.ui-button:link,
+.ui-button:visited,
+.ui-button:hover,
+.ui-button:active {
+	text-decoration: none;
+}
+/* to make room for the icon, a width needs to be set here */
+.ui-button-icon-only {
+	width: 2.2em;
+}
+/* button elements seem to need a little more width */
+button.ui-button-icon-only {
+	width: 2.4em;
+}
+.ui-button-icons-only {
+	width: 3.4em;
+}
+button.ui-button-icons-only {
+	width: 3.7em;
+}
+
+/* button text element */
+.ui-button .ui-button-text {
+	display: block;
+	line-height: normal;
+}
+.ui-button-text-only .ui-button-text {
+	padding: .4em 1em;
+}
+.ui-button-icon-only .ui-button-text,
+.ui-button-icons-only .ui-button-text {
+	padding: .4em;
+	text-indent: -9999999px;
+}
+.ui-button-text-icon-primary .ui-button-text,
+.ui-button-text-icons .ui-button-text {
+	padding: .4em 1em .4em 2.1em;
+}
+.ui-button-text-icon-secondary .ui-button-text,
+.ui-button-text-icons .ui-button-text {
+	padding: .4em 2.1em .4em 1em;
+}
+.ui-button-text-icons .ui-button-text {
+	padding-left: 2.1em;
+	padding-right: 2.1em;
+}
+/* no icon support for input elements, provide padding by default */
+input.ui-button {
+	padding: .4em 1em;
+}
+
+/* button icon element(s) */
+.ui-button-icon-only .ui-icon,
+.ui-button-text-icon-primary .ui-icon,
+.ui-button-text-icon-secondary .ui-icon,
+.ui-button-text-icons .ui-icon,
+.ui-button-icons-only .ui-icon {
+	position: absolute;
+	top: 50%;
+	margin-top: -8px;
+}
+.ui-button-icon-only .ui-icon {
+	left: 50%;
+	margin-left: -8px;
+}
+.ui-button-text-icon-primary .ui-button-icon-primary,
+.ui-button-text-icons .ui-button-icon-primary,
+.ui-button-icons-only .ui-button-icon-primary {
+	left: .5em;
+}
+.ui-button-text-icon-secondary .ui-button-icon-secondary,
+.ui-button-text-icons .ui-button-icon-secondary,
+.ui-button-icons-only .ui-button-icon-secondary {
+	right: .5em;
+}
+
+/* button sets */
+.ui-buttonset {
+	margin-right: 7px;
+}
+.ui-buttonset .ui-button {
+	margin-left: 0;
+	margin-right: -.3em;
+}
+
+/* workarounds */
+/* reset extra padding in Firefox, see h5bp.com/l */
+input.ui-button::-moz-focus-inner,
+button.ui-button::-moz-focus-inner {
+	border: 0;
+	padding: 0;
+}
+.ui-datepicker {
+	width: 17em;
+	padding: .2em .2em 0;
+	display: none;
+}
+.ui-datepicker .ui-datepicker-header {
+	position: relative;
+	padding: .2em 0;
+}
+.ui-datepicker .ui-datepicker-prev,
+.ui-datepicker .ui-datepicker-next {
+	position: absolute;
+	top: 2px;
+	width: 1.8em;
+	height: 1.8em;
+}
+.ui-datepicker .ui-datepicker-prev-hover,
+.ui-datepicker .ui-datepicker-next-hover {
+	top: 1px;
+}
+.ui-datepicker .ui-datepicker-prev {
+	left: 2px;
+}
+.ui-datepicker .ui-datepicker-next {
+	right: 2px;
+}
+.ui-datepicker .ui-datepicker-prev-hover {
+	left: 1px;
+}
+.ui-datepicker .ui-datepicker-next-hover {
+	right: 1px;
+}
+.ui-datepicker .ui-datepicker-prev span,
+.ui-datepicker .ui-datepicker-next span {
+	display: block;
+	position: absolute;
+	left: 50%;
+	margin-left: -8px;
+	top: 50%;
+	margin-top: -8px;
+}
+.ui-datepicker .ui-datepicker-title {
+	margin: 0 2.3em;
+	line-height: 1.8em;
+	text-align: center;
+}
+.ui-datepicker .ui-datepicker-title select {
+	font-size: 1em;
+	margin: 1px 0;
+}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year {
+	width: 45%;
+}
+.ui-datepicker table {
+	width: 100%;
+	font-size: .9em;
+	border-collapse: collapse;
+	margin: 0 0 .4em;
+}
+.ui-datepicker th {
+	padding: .7em .3em;
+	text-align: center;
+	font-weight: bold;
+	border: 0;
+}
+.ui-datepicker td {
+	border: 0;
+	padding: 1px;
+}
+.ui-datepicker td span,
+.ui-datepicker td a {
+	display: block;
+	padding: .2em;
+	text-align: right;
+	text-decoration: none;
+}
+.ui-datepicker .ui-datepicker-buttonpane {
+	background-image: none;
+	margin: .7em 0 0 0;
+	padding: 0 .2em;
+	border-left: 0;
+	border-right: 0;
+	border-bottom: 0;
+}
+.ui-datepicker .ui-datepicker-buttonpane button {
+	float: right;
+	margin: .5em .2em .4em;
+	cursor: pointer;
+	padding: .2em .6em .3em .6em;
+	width: auto;
+	overflow: visible;
+}
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
+	float: left;
+}
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi {
+	width: auto;
+}
+.ui-datepicker-multi .ui-datepicker-group {
+	float: left;
+}
+.ui-datepicker-multi .ui-datepicker-group table {
+	width: 95%;
+	margin: 0 auto .4em;
+}
+.ui-datepicker-multi-2 .ui-datepicker-group {
+	width: 50%;
+}
+.ui-datepicker-multi-3 .ui-datepicker-group {
+	width: 33.3%;
+}
+.ui-datepicker-multi-4 .ui-datepicker-group {
+	width: 25%;
+}
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
+	border-left-width: 0;
+}
+.ui-datepicker-multi .ui-datepicker-buttonpane {
+	clear: left;
+}
+.ui-datepicker-row-break {
+	clear: both;
+	width: 100%;
+	font-size: 0;
+}
+
+/* RTL support */
+.ui-datepicker-rtl {
+	direction: rtl;
+}
+.ui-datepicker-rtl .ui-datepicker-prev {
+	right: 2px;
+	left: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-next {
+	left: 2px;
+	right: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-prev:hover {
+	right: 1px;
+	left: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-next:hover {
+	left: 1px;
+	right: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane {
+	clear: right;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane button {
+	float: left;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
+.ui-datepicker-rtl .ui-datepicker-group {
+	float: right;
+}
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
+	border-right-width: 0;
+	border-left-width: 1px;
+}
+.ui-dialog {
+	overflow: hidden;
+	position: absolute;
+	top: 0;
+	left: 0;
+	padding: .2em;
+	outline: 0;
+}
+.ui-dialog .ui-dialog-titlebar {
+	padding: .4em 1em;
+	position: relative;
+}
+.ui-dialog .ui-dialog-title {
+	float: left;
+	margin: .1em 0;
+	white-space: nowrap;
+	width: 90%;
+	overflow: hidden;
+	text-overflow: ellipsis;
+}
+.ui-dialog .ui-dialog-titlebar-close {
+	position: absolute;
+	right: .3em;
+	top: 50%;
+	width: 20px;
+	margin: -10px 0 0 0;
+	padding: 1px;
+	height: 20px;
+}
+.ui-dialog .ui-dialog-content {
+	position: relative;
+	border: 0;
+	padding: .5em 1em;
+	background: none;
+	overflow: auto;
+}
+.ui-dialog .ui-dialog-buttonpane {
+	text-align: left;
+	border-width: 1px 0 0 0;
+	background-image: none;
+	margin-top: .5em;
+	padding: .3em 1em .5em .4em;
+}
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
+	float: right;
+}
+.ui-dialog .ui-dialog-buttonpane button {
+	margin: .5em .4em .5em 0;
+	cursor: pointer;
+}
+.ui-dialog .ui-resizable-se {
+	width: 12px;
+	height: 12px;
+	right: -5px;
+	bottom: -5px;
+	background-position: 16px 16px;
+}
+.ui-draggable .ui-dialog-titlebar {
+	cursor: move;
+}
+.ui-menu {
+	list-style: none;
+	padding: 0;
+	margin: 0;
+	display: block;
+	outline: none;
+}
+.ui-menu .ui-menu {
+	position: absolute;
+}
+.ui-menu .ui-menu-item {
+	position: relative;
+	margin: 0;
+	padding: 3px 1em 3px .4em;
+	cursor: pointer;
+	min-height: 0; /* support: IE7 */
+	/* support: IE10, see #8844 */
+	list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
+}
+.ui-menu .ui-menu-divider {
+	margin: 5px 0;
+	height: 0;
+	font-size: 0;
+	line-height: 0;
+	border-width: 1px 0 0 0;
+}
+.ui-menu .ui-state-focus,
+.ui-menu .ui-state-active {
+	margin: -1px;
+}
+
+/* icon support */
+.ui-menu-icons {
+	position: relative;
+}
+.ui-menu-icons .ui-menu-item {
+	padding-left: 2em;
+}
+
+/* left-aligned */
+.ui-menu .ui-icon {
+	position: absolute;
+	top: 0;
+	bottom: 0;
+	left: .2em;
+	margin: auto 0;
+}
+
+/* right-aligned */
+.ui-menu .ui-menu-icon {
+	left: auto;
+	right: 0;
+}
+.ui-progressbar {
+	height: 2em;
+	text-align: left;
+	overflow: hidden;
+}
+.ui-progressbar .ui-progressbar-value {
+	margin: -1px;
+	height: 100%;
+}
+.ui-progressbar .ui-progressbar-overlay {
+	background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");
+	height: 100%;
+	filter: alpha(opacity=25); /* support: IE8 */
+	opacity: 0.25;
+}
+.ui-progressbar-indeterminate .ui-progressbar-value {
+	background-image: none;
+}
+.ui-selectmenu-menu {
+	padding: 0;
+	margin: 0;
+	position: absolute;
+	top: 0;
+	left: 0;
+	display: none;
+}
+.ui-selectmenu-menu .ui-menu {
+	overflow: auto;
+	/* Support: IE7 */
+	overflow-x: hidden;
+	padding-bottom: 1px;
+}
+.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup {
+	font-size: 1em;
+	font-weight: bold;
+	line-height: 1.5;
+	padding: 2px 0.4em;
+	margin: 0.5em 0 0 0;
+	height: auto;
+	border: 0;
+}
+.ui-selectmenu-open {
+	display: block;
+}
+.ui-selectmenu-button {
+	display: inline-block;
+	overflow: hidden;
+	position: relative;
+	text-decoration: none;
+	cursor: pointer;
+}
+.ui-selectmenu-button span.ui-icon {
+	right: 0.5em;
+	left: auto;
+	margin-top: -8px;
+	position: absolute;
+	top: 50%;
+}
+.ui-selectmenu-button span.ui-selectmenu-text {
+	text-align: left;
+	padding: 0.4em 2.1em 0.4em 1em;
+	display: block;
+	line-height: 1.4;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+}
+.ui-slider {
+	position: relative;
+	text-align: left;
+}
+.ui-slider .ui-slider-handle {
+	position: absolute;
+	z-index: 2;
+	width: 1.2em;
+	height: 1.2em;
+	cursor: default;
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-slider .ui-slider-range {
+	position: absolute;
+	z-index: 1;
+	font-size: .7em;
+	display: block;
+	border: 0;
+	background-position: 0 0;
+}
+
+/* support: IE8 - See #6727 */
+.ui-slider.ui-state-disabled .ui-slider-handle,
+.ui-slider.ui-state-disabled .ui-slider-range {
+	filter: inherit;
+}
+
+.ui-slider-horizontal {
+	height: .8em;
+}
+.ui-slider-horizontal .ui-slider-handle {
+	top: -.3em;
+	margin-left: -.6em;
+}
+.ui-slider-horizontal .ui-slider-range {
+	top: 0;
+	height: 100%;
+}
+.ui-slider-horizontal .ui-slider-range-min {
+	left: 0;
+}
+.ui-slider-horizontal .ui-slider-range-max {
+	right: 0;
+}
+
+.ui-slider-vertical {
+	width: .8em;
+	height: 100px;
+}
+.ui-slider-vertical .ui-slider-handle {
+	left: -.3em;
+	margin-left: 0;
+	margin-bottom: -.6em;
+}
+.ui-slider-vertical .ui-slider-range {
+	left: 0;
+	width: 100%;
+}
+.ui-slider-vertical .ui-slider-range-min {
+	bottom: 0;
+}
+.ui-slider-vertical .ui-slider-range-max {
+	top: 0;
+}
+.ui-spinner {
+	position: relative;
+	display: inline-block;
+	overflow: hidden;
+	padding: 0;
+	vertical-align: middle;
+}
+.ui-spinner-input {
+	border: none;
+	background: none;
+	color: inherit;
+	padding: 0;
+	margin: .2em 0;
+	vertical-align: middle;
+	margin-left: .4em;
+	margin-right: 22px;
+}
+.ui-spinner-button {
+	width: 16px;
+	height: 50%;
+	font-size: .5em;
+	padding: 0;
+	margin: 0;
+	text-align: center;
+	position: absolute;
+	cursor: default;
+	display: block;
+	overflow: hidden;
+	right: 0;
+}
+/* more specificity required here to override default borders */
+.ui-spinner a.ui-spinner-button {
+	border-top: none;
+	border-bottom: none;
+	border-right: none;
+}
+/* vertically center icon */
+.ui-spinner .ui-icon {
+	position: absolute;
+	margin-top: -8px;
+	top: 50%;
+	left: 0;
+}
+.ui-spinner-up {
+	top: 0;
+}
+.ui-spinner-down {
+	bottom: 0;
+}
+
+/* TR overrides */
+.ui-spinner .ui-icon-triangle-1-s {
+	/* need to fix icons sprite */
+	background-position: -65px -16px;
+}
+.ui-tabs {
+	position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+	padding: .2em;
+}
+.ui-tabs .ui-tabs-nav {
+	margin: 0;
+	padding: .2em .2em 0;
+}
+.ui-tabs .ui-tabs-nav li {
+	list-style: none;
+	float: left;
+	position: relative;
+	top: 0;
+	margin: 1px .2em 0 0;
+	border-bottom-width: 0;
+	padding: 0;
+	white-space: nowrap;
+}
+.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
+	float: left;
+	padding: .5em 1em;
+	text-decoration: none;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active {
+	margin-bottom: -1px;
+	padding-bottom: 1px;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
+	cursor: text;
+}
+.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
+	cursor: pointer;
+}
+.ui-tabs .ui-tabs-panel {
+	display: block;
+	border-width: 0;
+	padding: 1em 1.4em;
+	background: none;
+}
+.ui-tooltip {
+	padding: 8px;
+	position: absolute;
+	z-index: 9999;
+	max-width: 300px;
+	-webkit-box-shadow: 0 0 5px #aaa;
+	box-shadow: 0 0 5px #aaa;
+}
+body .ui-tooltip {
+	border-width: 2px;
+}
diff --git a/htdocs/Libs/JQueryUI/jquery-ui.structure.min.css b/htdocs/Libs/JQueryUI/jquery-ui.structure.min.css
new file mode 100644
index 0000000..fdc9c07
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/jquery-ui.structure.min.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.11.4 - 2016-04-10
+* http://jqueryui.com
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;min-height:0;font-size:100%}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:none}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;cursor:pointer;min-height:0;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-button{display:inline-block;overflow:hidden;position:relative;text-decoration:none;cursor:pointer}.ui-selectmenu-button span.ui-icon{right:0.5em;left:auto;margin-top:-8px;position:absolute;top:50%}.ui-selectmenu-button span.ui-selectmenu-text{text-align:left;padding:0.4em 2.1em 0.4em 1em;display:block;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}
\ No newline at end of file
diff --git a/htdocs/Libs/JQueryUI/jquery-ui.theme.css b/htdocs/Libs/JQueryUI/jquery-ui.theme.css
new file mode 100644
index 0000000..add09e1
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/jquery-ui.theme.css
@@ -0,0 +1,410 @@
+/*!
+ * jQuery UI CSS Framework 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/theming/
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
+ */
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget {
+	font-family: Verdana,Arial,sans-serif;
+	font-size: 1.1em;
+}
+.ui-widget .ui-widget {
+	font-size: 1em;
+}
+.ui-widget input,
+.ui-widget select,
+.ui-widget textarea,
+.ui-widget button {
+	font-family: Verdana,Arial,sans-serif;
+	font-size: 1em;
+}
+.ui-widget-content {
+	border: 1px solid #aaaaaa;
+	background: #ffffff;
+	color: #222222;
+}
+.ui-widget-content a {
+	color: #222222;
+}
+.ui-widget-header {
+	border: 1px solid #aaaaaa;
+	background: #cccccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x;
+	color: #222222;
+	font-weight: bold;
+}
+.ui-widget-header a {
+	color: #222222;
+}
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default,
+.ui-widget-content .ui-state-default,
+.ui-widget-header .ui-state-default {
+	border: 1px solid #d3d3d3;
+	background: #e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x;
+	font-weight: normal;
+	color: #555555;
+}
+.ui-state-default a,
+.ui-state-default a:link,
+.ui-state-default a:visited {
+	color: #555555;
+	text-decoration: none;
+}
+.ui-state-hover,
+.ui-widget-content .ui-state-hover,
+.ui-widget-header .ui-state-hover,
+.ui-state-focus,
+.ui-widget-content .ui-state-focus,
+.ui-widget-header .ui-state-focus {
+	border: 1px solid #999999;
+	background: #dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x;
+	font-weight: normal;
+	color: #212121;
+}
+.ui-state-hover a,
+.ui-state-hover a:hover,
+.ui-state-hover a:link,
+.ui-state-hover a:visited,
+.ui-state-focus a,
+.ui-state-focus a:hover,
+.ui-state-focus a:link,
+.ui-state-focus a:visited {
+	color: #212121;
+	text-decoration: none;
+}
+.ui-state-active,
+.ui-widget-content .ui-state-active,
+.ui-widget-header .ui-state-active {
+	border: 1px solid #aaaaaa;
+	background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;
+	font-weight: normal;
+	color: #212121;
+}
+.ui-state-active a,
+.ui-state-active a:link,
+.ui-state-active a:visited {
+	color: #212121;
+	text-decoration: none;
+}
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight,
+.ui-widget-content .ui-state-highlight,
+.ui-widget-header .ui-state-highlight {
+	border: 1px solid #fcefa1;
+	background: #fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x;
+	color: #363636;
+}
+.ui-state-highlight a,
+.ui-widget-content .ui-state-highlight a,
+.ui-widget-header .ui-state-highlight a {
+	color: #363636;
+}
+.ui-state-error,
+.ui-widget-content .ui-state-error,
+.ui-widget-header .ui-state-error {
+	border: 1px solid #cd0a0a;
+	background: #fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;
+	color: #cd0a0a;
+}
+.ui-state-error a,
+.ui-widget-content .ui-state-error a,
+.ui-widget-header .ui-state-error a {
+	color: #cd0a0a;
+}
+.ui-state-error-text,
+.ui-widget-content .ui-state-error-text,
+.ui-widget-header .ui-state-error-text {
+	color: #cd0a0a;
+}
+.ui-priority-primary,
+.ui-widget-content .ui-priority-primary,
+.ui-widget-header .ui-priority-primary {
+	font-weight: bold;
+}
+.ui-priority-secondary,
+.ui-widget-content .ui-priority-secondary,
+.ui-widget-header .ui-priority-secondary {
+	opacity: .7;
+	filter:Alpha(Opacity=70); /* support: IE8 */
+	font-weight: normal;
+}
+.ui-state-disabled,
+.ui-widget-content .ui-state-disabled,
+.ui-widget-header .ui-state-disabled {
+	opacity: .35;
+	filter:Alpha(Opacity=35); /* support: IE8 */
+	background-image: none;
+}
+.ui-state-disabled .ui-icon {
+	filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
+}
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+	width: 16px;
+	height: 16px;
+}
+.ui-icon,
+.ui-widget-content .ui-icon {
+	background-image: url("images/ui-icons_222222_256x240.png");
+}
+.ui-widget-header .ui-icon {
+	background-image: url("images/ui-icons_222222_256x240.png");
+}
+.ui-state-default .ui-icon {
+	background-image: url("images/ui-icons_888888_256x240.png");
+}
+.ui-state-hover .ui-icon,
+.ui-state-focus .ui-icon {
+	background-image: url("images/ui-icons_454545_256x240.png");
+}
+.ui-state-active .ui-icon {
+	background-image: url("images/ui-icons_454545_256x240.png");
+}
+.ui-state-highlight .ui-icon {
+	background-image: url("images/ui-icons_2e83ff_256x240.png");
+}
+.ui-state-error .ui-icon,
+.ui-state-error-text .ui-icon {
+	background-image: url("images/ui-icons_cd0a0a_256x240.png");
+}
+
+/* positioning */
+.ui-icon-blank { background-position: 16px 16px; }
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-on { background-position: -96px -144px; }
+.ui-icon-radio-off { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-left,
+.ui-corner-tl {
+	border-top-left-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-right,
+.ui-corner-tr {
+	border-top-right-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-left,
+.ui-corner-bl {
+	border-bottom-left-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-right,
+.ui-corner-br {
+	border-bottom-right-radius: 4px;
+}
+
+/* Overlays */
+.ui-widget-overlay {
+	background: #aaaaaa;
+	opacity: .3;
+	filter: Alpha(Opacity=30); /* support: IE8 */
+}
+.ui-widget-shadow {
+	margin: -8px 0 0 -8px;
+	padding: 8px;
+	background: #aaaaaa;
+	opacity: .3;
+	filter: Alpha(Opacity=30); /* support: IE8 */
+	border-radius: 8px;
+}
diff --git a/htdocs/Libs/JQueryUI/jquery-ui.theme.min.css b/htdocs/Libs/JQueryUI/jquery-ui.theme.min.css
new file mode 100644
index 0000000..0263ac1
--- /dev/null
+++ b/htdocs/Libs/JQueryUI/jquery-ui.theme.min.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.11.4 - 2016-04-11
+* http://jqueryui.com
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_888888_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_454545_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_454545_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_2e83ff_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cd0a0a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#aaa;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px}
\ No newline at end of file
diff --git a/htdocs/Libs/JSONEditor/jsoneditor.custom.js b/htdocs/Libs/JSONEditor/jsoneditor.custom.js
new file mode 100644
index 0000000..19b8552
--- /dev/null
+++ b/htdocs/Libs/JSONEditor/jsoneditor.custom.js
@@ -0,0 +1,7679 @@
+/*! JSON Editor v0.7.23 - JSON Schema -> HTML Editor

+ * By Jeremy Dorn - https://github.com/jdorn/json-editor/

+ * Released under the MIT license

+ *

+ * Date: 2015-09-27

+ */

+

+/**

+ * See README.md for requirements and usage info

+ */

+

+(function() {

+

+    /*jshint loopfunc: true */

+    /* Simple JavaScript Inheritance

+     * By John Resig http://ejohn.org/

+     * MIT Licensed.

+     */

+    // Inspired by base2 and Prototype

+    var Class;

+    (function() {

+        var initializing = false,

+            fnTest = /xyz/.test(function() {

+                window.postMessage("xyz");

+            }) ? /\b_super\b/ : /.*/;

+

+        // The base Class implementation (does nothing)

+        Class = function() {};

+

+        // Create a new Class that inherits from this class

+        Class.extend = function(prop) {

+            var _super = this.prototype;

+

+            // Instantiate a base class (but only create the instance,

+            // don't run the init constructor)

+            initializing = true;

+            var prototype = new this();

+            initializing = false;

+

+            // Copy the properties over onto the new prototype

+            for (var name in prop) {

+                // Check if we're overwriting an existing function

+                prototype[name] = typeof prop[name] == "function" &&

+                    typeof _super[name] == "function" && fnTest.test(prop[name]) ?

+                    (function(name, fn) {

+                    return function() {

+                        var tmp = this._super;

+

+                        // Add a new ._super() method that is the same method

+                        // but on the super-class

+                        this._super = _super[name];

+

+                        // The method only need to be bound temporarily, so we

+                        // remove it when we're done executing

+                        var ret = fn.apply(this, arguments);

+                        this._super = tmp;

+

+                        return ret;

+                    };

+                })(name, prop[name]) :

+                    prop[name];

+            }

+

+            // The dummy class constructor

+

+            function Class() {

+                // All construction is actually done in the init method

+                if (!initializing && this.init)

+                    this.init.apply(this, arguments);

+            }

+

+            // Populate our constructed prototype object

+            Class.prototype = prototype;

+

+            // Enforce the constructor to be what we expect

+            Class.prototype.constructor = Class;

+

+            // And make this class extendable

+            Class.extend = arguments.callee;

+

+            return Class;

+        };

+

+        return Class;

+    })();

+

+    // CustomEvent constructor polyfill

+    // From MDN

+    (function() {

+        function CustomEvent(event, params) {

+            params = params || {

+                bubbles: false,

+                cancelable: false,

+                detail: undefined

+            };

+            var evt = document.createEvent('CustomEvent');

+            evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);

+            return evt;

+        }

+

+        CustomEvent.prototype = window.Event.prototype;

+

+        window.CustomEvent = CustomEvent;

+    })();

+

+    // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel

+    // MIT license

+    (function() {

+        var lastTime = 0;

+        var vendors = ['ms', 'moz', 'webkit', 'o'];

+        for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {

+            window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];

+            window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||

+                window[vendors[x] + 'CancelRequestAnimationFrame'];

+        }

+

+        if (!window.requestAnimationFrame)

+            window.requestAnimationFrame = function(callback, element) {

+                var currTime = new Date().getTime();

+                var timeToCall = Math.max(0, 16 - (currTime - lastTime));

+                var id = window.setTimeout(function() {

+                        callback(currTime + timeToCall);

+                    },

+                    timeToCall);

+                lastTime = currTime + timeToCall;

+                return id;

+            };

+

+        if (!window.cancelAnimationFrame)

+            window.cancelAnimationFrame = function(id) {

+                clearTimeout(id);

+            };

+    }());

+

+    // Array.isArray polyfill

+    // From MDN

+    (function() {

+        if (!Array.isArray) {

+            Array.isArray = function(arg) {

+                return Object.prototype.toString.call(arg) === '[object Array]';

+            };

+        }

+    }());

+    /**

+     * Taken from jQuery 2.1.3

+     *

+     * @param obj

+     * @returns {boolean}

+     */

+    var $isplainobject = function(obj) {

+        // Not plain objects:

+        // - Any object or value whose internal [[Class]] property is not "[object Object]"

+        // - DOM nodes

+        // - window

+        if (typeof obj !== "object" || obj.nodeType || (obj !== null && obj === obj.window)) {

+            return false;

+        }

+

+        if (obj.constructor && !Object.prototype.hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf")) {

+            return false;

+        }

+

+        // If the function hasn't returned already, we're confident that

+        // |obj| is a plain object, created by {} or constructed with new Object

+        return true;

+    };

+

+    var $extend = function(destination) {

+        var source, i, property;

+        for (i = 1; i < arguments.length; i++) {

+            source = arguments[i];

+            for (property in source) {

+                if (!source.hasOwnProperty(property)) continue;

+                if (source[property] && $isplainobject(source[property])) {

+                    if (!destination.hasOwnProperty(property)) destination[property] = {};

+                    $extend(destination[property], source[property]);

+                } else {

+                    destination[property] = source[property];

+                }

+            }

+        }

+        return destination;

+    };

+

+    var $each = function(obj, callback) {

+        if (!obj || typeof obj !== "object") return;

+        var i;

+        if (Array.isArray(obj) || (typeof obj.length === 'number' && obj.length > 0 && (obj.length - 1) in obj)) {

+            for (i = 0; i < obj.length; i++) {

+                if (callback(i, obj[i]) === false) return;

+            }

+        } else {

+            if (Object.keys) {

+                var keys = Object.keys(obj);

+                for (i = 0; i < keys.length; i++) {

+                    if (callback(keys[i], obj[keys[i]]) === false) return;

+                }

+            } else {

+                for (i in obj) {

+                    if (!obj.hasOwnProperty(i)) continue;

+                    if (callback(i, obj[i]) === false) return;

+                }

+            }

+        }

+    };

+

+    var $trigger = function(el, event) {

+        var e = document.createEvent('HTMLEvents');

+        e.initEvent(event, true, true);

+        el.dispatchEvent(e);

+    };

+    var $triggerc = function(el, event) {

+        var e = new CustomEvent(event, {

+            bubbles: true,

+            cancelable: true

+        });

+

+        el.dispatchEvent(e);

+    };

+

+    var JSONEditor = function(element, options) {

+        if (!(element instanceof Element)) {

+            throw new Error('element should be an instance of Element');

+        }

+        options = $extend({}, JSONEditor.defaults.options, options || {});

+        this.element = element;

+        this.options = options;

+        this.init();

+    };

+    JSONEditor.prototype = {

+        // necessary since we remove the ctor property by doing a literal assignment. Without this

+        // the $isplainobject function will think that this is a plain object.

+        constructor: JSONEditor,

+        init: function() {

+            var self = this;

+

+            this.ready = false;

+

+            var theme_class = JSONEditor.defaults.themes[this.options.theme || JSONEditor.defaults.theme];

+            if (!theme_class) throw "Unknown theme " + (this.options.theme || JSONEditor.defaults.theme);

+

+            this.schema = this.options.schema;

+            this.theme = new theme_class();

+            this.template = this.options.template;

+            this.refs = this.options.refs || {};

+            this.uuid = 0;

+            this.__data = {};

+

+            var icon_class = JSONEditor.defaults.iconlibs[this.options.iconlib || JSONEditor.defaults.iconlib];

+            if (icon_class) this.iconlib = new icon_class();

+

+            this.root_container = this.theme.getContainer();

+            this.element.appendChild(this.root_container);

+

+            this.translate = this.options.translate || JSONEditor.defaults.translate;

+

+            // Fetch all external refs via ajax

+            this._loadExternalRefs(this.schema, function() {

+                self._getDefinitions(self.schema);

+

+                // Validator options

+                var validator_options = {};

+                if (self.options.custom_validators) {

+                    validator_options.custom_validators = self.options.custom_validators;

+                }

+                self.validator = new JSONEditor.Validator(self, null, validator_options);

+

+                // Create the root editor

+                var editor_class = self.getEditorClass(self.schema);

+                self.root = self.createEditor(editor_class, {

+                    jsoneditor: self,

+                    schema: self.schema,

+                    required: true,

+                    container: self.root_container

+                });

+

+                self.root.preBuild();

+                self.root.build();

+                self.root.postBuild();

+

+                // Starting data

+                if (self.options.startval) self.root.setValue(self.options.startval);

+

+                self.validation_results = self.validator.validate(self.root.getValue());

+                self.root.showValidationErrors(self.validation_results);

+                self.ready = true;

+

+                // Fire ready event asynchronously

+                window.requestAnimationFrame(function() {

+                    if (!self.ready) return;

+                    self.validation_results = self.validator.validate(self.root.getValue());

+                    self.root.showValidationErrors(self.validation_results);

+                    self.trigger('ready');

+                    self.trigger('change');

+                });

+            });

+        },

+        getValue: function() {

+            if (!this.ready) throw "JSON Editor not ready yet.  Listen for 'ready' event before getting the value";

+

+            return this.root.getValue();

+        },

+        setValue: function(value) {

+            if (!this.ready) throw "JSON Editor not ready yet.  Listen for 'ready' event before setting the value";

+

+            this.root.setValue(value);

+            return this;

+        },

+        validate: function(value) {

+            if (!this.ready) throw "JSON Editor not ready yet.  Listen for 'ready' event before validating";

+

+            // Custom value

+            if (arguments.length === 1) {

+                return this.validator.validate(value);

+            }

+            // Current value (use cached result)

+            else {

+                return this.validation_results;

+            }

+        },

+        destroy: function() {

+            if (this.destroyed) return;

+            if (!this.ready) return;

+

+            this.schema = null;

+            this.options = null;

+            this.root.destroy();

+            this.root = null;

+            this.root_container = null;

+            this.validator = null;

+            this.validation_results = null;

+            this.theme = null;

+            this.iconlib = null;

+            this.template = null;

+            this.__data = null;

+            this.ready = false;

+            this.element.innerHTML = '';

+

+            this.destroyed = true;

+        },

+        on: function(event, callback) {

+            this.callbacks = this.callbacks || {};

+            this.callbacks[event] = this.callbacks[event] || [];

+            this.callbacks[event].push(callback);

+

+            return this;

+        },

+        off: function(event, callback) {

+            // Specific callback

+            if (event && callback) {

+                this.callbacks = this.callbacks || {};

+                this.callbacks[event] = this.callbacks[event] || [];

+                var newcallbacks = [];

+                for (var i = 0; i < this.callbacks[event].length; i++) {

+                    if (this.callbacks[event][i] === callback) continue;

+                    newcallbacks.push(this.callbacks[event][i]);

+                }

+                this.callbacks[event] = newcallbacks;

+            }

+            // All callbacks for a specific event

+            else if (event) {

+                this.callbacks = this.callbacks || {};

+                this.callbacks[event] = [];

+            }

+            // All callbacks for all events

+            else {

+                this.callbacks = {};

+            }

+

+            return this;

+        },

+        trigger: function(event) {

+            if (this.callbacks && this.callbacks[event] && this.callbacks[event].length) {

+                for (var i = 0; i < this.callbacks[event].length; i++) {

+                    this.callbacks[event][i]();

+                }

+            }

+

+            return this;

+        },

+        setOption: function(option, value) {

+            if (option === "show_errors") {

+                this.options.show_errors = value;

+                this.onChange();

+            }

+            // Only the `show_errors` option is supported for now

+            else {

+                throw "Option " + option + " must be set during instantiation and cannot be changed later";

+            }

+

+            return this;

+        },

+        getEditorClass: function(schema) {

+            var classname;

+

+            schema = this.expandSchema(schema);

+

+            $each(JSONEditor.defaults.resolvers, function(i, resolver) {

+                var tmp = resolver(schema);

+                if (tmp) {

+                    if (JSONEditor.defaults.editors[tmp]) {

+                        classname = tmp;

+                        return false;

+                    }

+                }

+            });

+

+            if (!classname) throw "Unknown editor for schema " + JSON.stringify(schema);

+            if (!JSONEditor.defaults.editors[classname]) throw "Unknown editor " + classname;

+

+            return JSONEditor.defaults.editors[classname];

+        },

+        createEditor: function(editor_class, options) {

+            options = $extend({}, editor_class.options || {}, options);

+            return new editor_class(options);

+        },

+        onChange: function() {

+            if (!this.ready) return;

+

+            if (this.firing_change) return;

+            this.firing_change = true;

+

+            var self = this;

+

+            window.requestAnimationFrame(function() {

+                self.firing_change = false;

+                if (!self.ready) return;

+

+                // Validate and cache results

+                self.validation_results = self.validator.validate(self.root.getValue());

+

+                if (self.options.show_errors !== "never") {

+                    self.root.showValidationErrors(self.validation_results);

+                } else {

+                    self.root.showValidationErrors([]);

+                }

+

+                // Fire change event

+                self.trigger('change');

+            });

+

+            return this;

+        },

+        compileTemplate: function(template, name) {

+            name = name || JSONEditor.defaults.template;

+

+            var engine;

+

+            // Specifying a preset engine

+            if (typeof name === 'string') {

+                if (!JSONEditor.defaults.templates[name]) throw "Unknown template engine " + name;

+                engine = JSONEditor.defaults.templates[name]();

+

+                if (!engine) throw "Template engine " + name + " missing required library.";

+            }

+            // Specifying a custom engine

+            else {

+                engine = name;

+            }

+

+            if (!engine) throw "No template engine set";

+            if (!engine.compile) throw "Invalid template engine set";

+

+            return engine.compile(template);

+        },

+        _data: function(el, key, value) {

+            // Setting data

+            if (arguments.length === 3) {

+                var uuid;

+                if (el.hasAttribute('data-jsoneditor-' + key)) {

+                    uuid = el.getAttribute('data-jsoneditor-' + key);

+                } else {

+                    uuid = this.uuid++;

+                    el.setAttribute('data-jsoneditor-' + key, uuid);

+                }

+

+                this.__data[uuid] = value;

+            }

+            // Getting data

+            else {

+                // No data stored

+                if (!el.hasAttribute('data-jsoneditor-' + key)) return null;

+

+                return this.__data[el.getAttribute('data-jsoneditor-' + key)];

+            }

+        },

+        registerEditor: function(editor) {

+            this.editors = this.editors || {};

+            this.editors[editor.path] = editor;

+            return this;

+        },

+        unregisterEditor: function(editor) {

+            this.editors = this.editors || {};

+            this.editors[editor.path] = null;

+            return this;

+        },

+        getEditor: function(path) {

+            if (!this.editors) return;

+            return this.editors[path];

+        },

+        watch: function(path, callback) {

+            this.watchlist = this.watchlist || {};

+            this.watchlist[path] = this.watchlist[path] || [];

+            this.watchlist[path].push(callback);

+

+            return this;

+        },

+        unwatch: function(path, callback) {

+            if (!this.watchlist || !this.watchlist[path]) return this;

+            // If removing all callbacks for a path

+            if (!callback) {

+                this.watchlist[path] = null;

+                return this;

+            }

+

+            var newlist = [];

+            for (var i = 0; i < this.watchlist[path].length; i++) {

+                if (this.watchlist[path][i] === callback) continue;

+                else newlist.push(this.watchlist[path][i]);

+            }

+            this.watchlist[path] = newlist.length ? newlist : null;

+            return this;

+        },

+        notifyWatchers: function(path) {

+            if (!this.watchlist || !this.watchlist[path]) return this;

+            for (var i = 0; i < this.watchlist[path].length; i++) {

+                this.watchlist[path][i]();

+            }

+        },

+        isEnabled: function() {

+            return !this.root || this.root.isEnabled();

+        },

+        enable: function() {

+            this.root.enable();

+        },

+        disable: function() {

+            this.root.disable();

+        },

+        _getDefinitions: function(schema, path) {

+            path = path || '#/definitions/';

+            if (schema.definitions) {

+                for (var i in schema.definitions) {

+                    if (!schema.definitions.hasOwnProperty(i)) continue;

+                    this.refs[path + i] = schema.definitions[i];

+                    if (schema.definitions[i].definitions) {

+                        this._getDefinitions(schema.definitions[i], path + i + '/definitions/');

+                    }

+                }

+            }

+        },

+        _getExternalRefs: function(schema) {

+            var refs = {};

+            var merge_refs = function(newrefs) {

+                for (var i in newrefs) {

+                    if (newrefs.hasOwnProperty(i)) {

+                        refs[i] = true;

+                    }

+                }

+            };

+

+            if (schema.$ref && typeof schema.$ref !== "object" && schema.$ref.substr(0, 1) !== "#" && !this.refs[schema.$ref]) {

+                refs[schema.$ref] = true;

+            }

+

+            for (var i in schema) {

+                if (!schema.hasOwnProperty(i)) continue;

+                if (schema[i] && typeof schema[i] === "object" && Array.isArray(schema[i])) {

+                    for (var j = 0; j < schema[i].length; j++) {

+                        if (typeof schema[i][j] === "object") {

+                            merge_refs(this._getExternalRefs(schema[i][j]));

+                        }

+                    }

+                } else if (schema[i] && typeof schema[i] === "object") {

+                    merge_refs(this._getExternalRefs(schema[i]));

+                }

+            }

+

+            return refs;

+        },

+        _loadExternalRefs: function(schema, callback) {

+            var self = this;

+            var refs = this._getExternalRefs(schema);

+

+            var done = 0,

+                waiting = 0,

+                callback_fired = false;

+

+            $each(refs, function(url) {

+                if (self.refs[url]) return;

+                if (!self.options.ajax) throw "Must set ajax option to true to load external ref " + url;

+                self.refs[url] = 'loading';

+                waiting++;

+

+                var r = new XMLHttpRequest();

+                r.open("GET", url, true);

+                r.onreadystatechange = function() {

+                    if (r.readyState != 4) return;

+                    // Request succeeded

+                    if (r.status === 200) {

+                        var response;

+                        try {

+                            response = JSON.parse(r.responseText);

+                        } catch (e) {

+                            window.console.log(e);

+                            throw "Failed to parse external ref " + url;

+                        }

+                        if (!response || typeof response !== "object") throw "External ref does not contain a valid schema - " + url;

+

+                        self.refs[url] = response;

+                        self._loadExternalRefs(response, function() {

+                            done++;

+                            if (done >= waiting && !callback_fired) {

+                                callback_fired = true;

+                                callback();

+                            }

+                        });

+                    }

+                    // Request failed

+                    else {

+                        window.console.log(r);

+                        throw "Failed to fetch ref via ajax- " + url;

+                    }

+                };

+                r.send();

+            });

+

+            if (!waiting) {

+                callback();

+            }

+        },

+        expandRefs: function(schema) {

+            schema = $extend({}, schema);

+

+            while (schema.$ref) {

+                var ref = schema.$ref;

+                delete schema.$ref;

+

+                if (!this.refs[ref]) ref = decodeURIComponent(ref);

+

+                schema = this.extendSchemas(schema, this.refs[ref]);

+            }

+            return schema;

+        },

+        expandSchema: function(schema) {

+            var self = this;

+            var extended = $extend({}, schema);

+            var i;

+

+            // Version 3 `type`

+            if (typeof schema.type === 'object') {

+                // Array of types

+                if (Array.isArray(schema.type)) {

+                    $each(schema.type, function(key, value) {

+                        // Schema

+                        if (typeof value === 'object') {

+                            schema.type[key] = self.expandSchema(value);

+                        }

+                    });

+                }

+                // Schema

+                else {

+                    schema.type = self.expandSchema(schema.type);

+                }

+            }

+            // Version 3 `disallow`

+            if (typeof schema.disallow === 'object') {

+                // Array of types

+                if (Array.isArray(schema.disallow)) {

+                    $each(schema.disallow, function(key, value) {

+                        // Schema

+                        if (typeof value === 'object') {

+                            schema.disallow[key] = self.expandSchema(value);

+                        }

+                    });

+                }

+                // Schema

+                else {

+                    schema.disallow = self.expandSchema(schema.disallow);

+                }

+            }

+            // Version 4 `anyOf`

+            if (schema.anyOf) {

+                $each(schema.anyOf, function(key, value) {

+                    schema.anyOf[key] = self.expandSchema(value);

+                });

+            }

+            // Version 4 `dependencies` (schema dependencies)

+            if (schema.dependencies) {

+                $each(schema.dependencies, function(key, value) {

+                    if (typeof value === "object" && !(Array.isArray(value))) {

+                        schema.dependencies[key] = self.expandSchema(value);

+                    }

+                });

+            }

+            // Version 4 `not`

+            if (schema.not) {

+                schema.not = this.expandSchema(schema.not);

+            }

+

+            // allOf schemas should be merged into the parent

+            if (schema.allOf) {

+                for (i = 0; i < schema.allOf.length; i++) {

+                    extended = this.extendSchemas(extended, this.expandSchema(schema.allOf[i]));

+                }

+                delete extended.allOf;

+            }

+            // extends schemas should be merged into parent

+            if (schema["extends"]) {

+                // If extends is a schema

+                if (!(Array.isArray(schema["extends"]))) {

+                    extended = this.extendSchemas(extended, this.expandSchema(schema["extends"]));

+                }

+                // If extends is an array of schemas

+                else {

+                    for (i = 0; i < schema["extends"].length; i++) {

+                        extended = this.extendSchemas(extended, this.expandSchema(schema["extends"][i]));

+                    }

+                }

+                delete extended["extends"];

+            }

+            // parent should be merged into oneOf schemas

+            if (schema.oneOf) {

+                var tmp = $extend({}, extended);

+                delete tmp.oneOf;

+                for (i = 0; i < schema.oneOf.length; i++) {

+                    extended.oneOf[i] = this.extendSchemas(this.expandSchema(schema.oneOf[i]), tmp);

+                }

+            }

+

+            return this.expandRefs(extended);

+        },

+        extendSchemas: function(obj1, obj2) {

+            obj1 = $extend({}, obj1);

+            obj2 = $extend({}, obj2);

+

+            var self = this;

+            var extended = {};

+            $each(obj1, function(prop, val) {

+                // If this key is also defined in obj2, merge them

+                if (typeof obj2[prop] !== "undefined") {

+                    // Required arrays should be unioned together

+                    if (prop === 'required' && typeof val === "object" && Array.isArray(val)) {

+                        // Union arrays and unique

+                        extended.required = val.concat(obj2[prop]).reduce(function(p, c) {

+                            if (p.indexOf(c) < 0) p.push(c);

+                            return p;

+                        }, []);

+                    }

+                    // Type should be intersected and is either an array or string

+                    else if (prop === 'type' && (typeof val === "string" || Array.isArray(val))) {

+                        // Make sure we're dealing with arrays

+                        if (typeof val === "string") val = [val];

+                        if (typeof obj2.type === "string") obj2.type = [obj2.type];

+

+

+                        extended.type = val.filter(function(n) {

+                            return obj2.type.indexOf(n) !== -1;

+                        });

+

+                        // If there's only 1 type and it's a primitive, use a string instead of array

+                        if (extended.type.length === 1 && typeof extended.type[0] === "string") {

+                            extended.type = extended.type[0];

+                        }

+                    }

+                    // All other arrays should be intersected (enum, etc.)

+                    else if (typeof val === "object" && Array.isArray(val)) {

+                        extended[prop] = val.filter(function(n) {

+                            return obj2[prop].indexOf(n) !== -1;

+                        });

+                    }

+                    // Objects should be recursively merged

+                    else if (typeof val === "object" && val !== null) {

+                        extended[prop] = self.extendSchemas(val, obj2[prop]);

+                    }

+                    // Otherwise, use the first value

+                    else {

+                        extended[prop] = val;

+                    }

+                }

+                // Otherwise, just use the one in obj1

+                else {

+                    extended[prop] = val;

+                }

+            });

+            // Properties in obj2 that aren't in obj1

+            $each(obj2, function(prop, val) {

+                if (typeof obj1[prop] === "undefined") {

+                    extended[prop] = val;

+                }

+            });

+

+            return extended;

+        }

+    };

+

+    JSONEditor.defaults = {

+        themes: {},

+        templates: {},

+        iconlibs: {},

+        editors: {},

+        languages: {},

+        resolvers: [],

+        custom_validators: []

+    };

+

+    JSONEditor.Validator = Class.extend({

+        init: function(jsoneditor, schema, options) {

+            this.jsoneditor = jsoneditor;

+            this.schema = schema || this.jsoneditor.schema;

+            this.options = options || {};

+            this.translate = this.jsoneditor.translate || JSONEditor.defaults.translate;

+        },

+        validate: function(value) {

+            return this._validateSchema(this.schema, value);

+        },

+        _validateSchema: function(schema, value, path) {

+            var self = this;

+            var errors = [];

+            var valid, i, j;

+            var stringified = JSON.stringify(value);

+

+            path = path || 'root';

+

+            // Work on a copy of the schema

+            schema = $extend({}, this.jsoneditor.expandRefs(schema));

+

+            /*

+             * Type Agnostic Validation

+             */

+

+            // Version 3 `required`

+            if (schema.required && schema.required === true) {

+                if (typeof value === "undefined") {

+                    errors.push({

+                        path: path,

+                        property: 'required',

+                        message: this.translate("error_notset")

+                    });

+

+                    // Can't do any more validation at this point

+                    return errors;

+                }

+            }

+            // Value not defined

+            else if (typeof value === "undefined") {

+                // If required_by_default is set, all fields are required

+                if (this.jsoneditor.options.required_by_default) {

+                    errors.push({

+                        path: path,

+                        property: 'required',

+                        message: this.translate("error_notset")

+                    });

+                }

+                // Not required, no further validation needed

+                else {

+                    return errors;

+                }

+            }

+

+            // `enum`

+            if (schema["enum"]) {

+                valid = false;

+                for (i = 0; i < schema["enum"].length; i++) {

+                    if (stringified === JSON.stringify(schema["enum"][i])) valid = true;

+                }

+                if (!valid) {

+                    errors.push({

+                        path: path,

+                        property: 'enum',

+                        message: this.translate("error_enum")

+                    });

+                }

+            }

+

+            // `extends` (version 3)

+            if (schema["extends"]) {

+                for (i = 0; i < schema["extends"].length; i++) {

+                    errors = errors.concat(this._validateSchema(schema["extends"][i], value, path));

+                }

+            }

+

+            // `allOf`

+            if (schema.allOf) {

+                for (i = 0; i < schema.allOf.length; i++) {

+                    errors = errors.concat(this._validateSchema(schema.allOf[i], value, path));

+                }

+            }

+

+            // `anyOf`

+            if (schema.anyOf) {

+                valid = false;

+                for (i = 0; i < schema.anyOf.length; i++) {

+                    if (!this._validateSchema(schema.anyOf[i], value, path).length) {

+                        valid = true;

+                        break;

+                    }

+                }

+                if (!valid) {

+                    errors.push({

+                        path: path,

+                        property: 'anyOf',

+                        message: this.translate('error_anyOf')

+                    });

+                }

+            }

+

+            // `oneOf`

+            if (schema.oneOf) {

+                valid = 0;

+                var oneof_errors = [];

+                for (i = 0; i < schema.oneOf.length; i++) {

+                    // Set the error paths to be path.oneOf[i].rest.of.path

+                    var tmp = this._validateSchema(schema.oneOf[i], value, path);

+                    if (!tmp.length) {

+                        valid++;

+                    }

+

+                    for (j = 0; j < tmp.length; j++) {

+                        tmp[j].path = path + '.oneOf[' + i + ']' + tmp[j].path.substr(path.length);

+                    }

+                    oneof_errors = oneof_errors.concat(tmp);

+

+                }

+                if (valid !== 1) {

+                    errors.push({

+                        path: path,

+                        property: 'oneOf',

+                        message: this.translate('error_oneOf', [valid])

+                    });

+                    errors = errors.concat(oneof_errors);

+                }

+            }

+

+            // `not`

+            if (schema.not) {

+                if (!this._validateSchema(schema.not, value, path).length) {

+                    errors.push({

+                        path: path,

+                        property: 'not',

+                        message: this.translate('error_not')

+                    });

+                }

+            }

+

+            // `type` (both Version 3 and Version 4 support)

+            if (schema.type) {

+                // Union type

+                if (Array.isArray(schema.type)) {

+                    valid = false;

+                    for (i = 0; i < schema.type.length; i++) {

+                        if (this._checkType(schema.type[i], value)) {

+                            valid = true;

+                            break;

+                        }

+                    }

+                    if (!valid) {

+                        errors.push({

+                            path: path,

+                            property: 'type',

+                            message: this.translate('error_type_union')

+                        });

+                    }

+                }

+                // Simple type

+                else {

+                    if (!this._checkType(schema.type, value)) {

+                        errors.push({

+                            path: path,

+                            property: 'type',

+                            message: this.translate('error_type', [schema.type])

+                        });

+                    }

+                }

+            }

+

+

+            // `disallow` (version 3)

+            if (schema.disallow) {

+                // Union type

+                if (Array.isArray(schema.disallow)) {

+                    valid = true;

+                    for (i = 0; i < schema.disallow.length; i++) {

+                        if (this._checkType(schema.disallow[i], value)) {

+                            valid = false;

+                            break;

+                        }

+                    }

+                    if (!valid) {

+                        errors.push({

+                            path: path,

+                            property: 'disallow',

+                            message: this.translate('error_disallow_union')

+                        });

+                    }

+                }

+                // Simple type

+                else {

+                    if (this._checkType(schema.disallow, value)) {

+                        errors.push({

+                            path: path,

+                            property: 'disallow',

+                            message: this.translate('error_disallow', [schema.disallow])

+                        });

+                    }

+                }

+            }

+

+            /*

+             * Type Specific Validation

+             */

+

+            // Number Specific Validation

+            if (typeof value === "number") {

+                // `multipleOf` and `divisibleBy`

+                if (schema.multipleOf || schema.divisibleBy) {

+                    valid = value / (schema.multipleOf || schema.divisibleBy);

+                    if (valid !== Math.floor(valid)) {

+                        errors.push({

+                            path: path,

+                            property: schema.multipleOf ? 'multipleOf' : 'divisibleBy',

+                            message: this.translate('error_multipleOf', [schema.multipleOf || schema.divisibleBy])

+                        });

+                    }

+                }

+

+                // `maximum`

+                if (schema.hasOwnProperty('maximum')) {

+                    if (schema.exclusiveMaximum && value >= schema.maximum) {

+                        errors.push({

+                            path: path,

+                            property: 'maximum',

+                            message: this.translate('error_maximum_excl', [schema.maximum])

+                        });

+                    } else if (!schema.exclusiveMaximum && value > schema.maximum) {

+                        errors.push({

+                            path: path,

+                            property: 'maximum',

+                            message: this.translate('error_maximum_incl', [schema.maximum])

+                        });

+                    }

+                }

+

+                // `minimum`

+                if (schema.hasOwnProperty('minimum')) {

+                    if (schema.exclusiveMinimum && value <= schema.minimum) {

+                        errors.push({

+                            path: path,

+                            property: 'minimum',

+                            message: this.translate('error_minimum_excl', [schema.minimum])

+                        });

+                    } else if (!schema.exclusiveMinimum && value < schema.minimum) {

+                        errors.push({

+                            path: path,

+                            property: 'minimum',

+                            message: this.translate('error_minimum_incl', [schema.minimum])

+                        });

+                    }

+                }

+            }

+            // String specific validation

+            else if (typeof value === "string") {

+                // `maxLength`

+                if (schema.maxLength) {

+                    if ((value + "").length > schema.maxLength) {

+                        errors.push({

+                            path: path,

+                            property: 'maxLength',

+                            message: this.translate('error_maxLength', [schema.maxLength])

+                        });

+                    }

+                }

+

+                // `minLength`

+                if (schema.minLength) {

+                    if ((value + "").length < schema.minLength) {

+                        errors.push({

+                            path: path,

+                            property: 'minLength',

+                            message: this.translate((schema.minLength === 1 ? 'error_notempty' : 'error_minLength'), [schema.minLength])

+                        });

+                    }

+                }

+

+                // `pattern`

+                if (schema.pattern) {

+                    if (!(new RegExp(schema.pattern)).test(value)) {

+                        errors.push({

+                            path: path,

+                            property: 'pattern',

+                            message: this.translate('error_pattern')

+                        });

+                    }

+                }

+            }

+            // Array specific validation

+            else if (typeof value === "object" && value !== null && Array.isArray(value)) {

+                // `items` and `additionalItems`

+                if (schema.items) {

+                    // `items` is an array

+                    if (Array.isArray(schema.items)) {

+                        for (i = 0; i < value.length; i++) {

+                            // If this item has a specific schema tied to it

+                            // Validate against it

+                            if (schema.items[i]) {

+                                errors = errors.concat(this._validateSchema(schema.items[i], value[i], path + '.' + i));

+                            }

+                            // If all additional items are allowed

+                            else if (schema.additionalItems === true) {

+                                break;

+                            }

+                            // If additional items is a schema

+                            // TODO: Incompatibility between version 3 and 4 of the spec

+                            else if (schema.additionalItems) {

+                                errors = errors.concat(this._validateSchema(schema.additionalItems, value[i], path + '.' + i));

+                            }

+                            // If no additional items are allowed

+                            else if (schema.additionalItems === false) {

+                                errors.push({

+                                    path: path,

+                                    property: 'additionalItems',

+                                    message: this.translate('error_additionalItems')

+                                });

+                                break;

+                            }

+                            // Default for `additionalItems` is an empty schema

+                            else {

+                                break;

+                            }

+                        }

+                    }

+                    // `items` is a schema

+                    else {

+                        // Each item in the array must validate against the schema

+                        for (i = 0; i < value.length; i++) {

+                            errors = errors.concat(this._validateSchema(schema.items, value[i], path + '.' + i));

+                        }

+                    }

+                }

+

+                // `maxItems`

+                if (schema.maxItems) {

+                    if (value.length > schema.maxItems) {

+                        errors.push({

+                            path: path,

+                            property: 'maxItems',

+                            message: this.translate('error_maxItems', [schema.maxItems])

+                        });

+                    }

+                }

+

+                // `minItems`

+                if (schema.minItems) {

+                    if (value.length < schema.minItems) {

+                        errors.push({

+                            path: path,

+                            property: 'minItems',

+                            message: this.translate('error_minItems', [schema.minItems])

+                        });

+                    }

+                }

+

+                // `uniqueItems`

+                if (schema.uniqueItems) {

+                    var seen = {};

+                    for (i = 0; i < value.length; i++) {

+                        valid = JSON.stringify(value[i]);

+                        if (seen[valid]) {

+                            errors.push({

+                                path: path,

+                                property: 'uniqueItems',

+                                message: this.translate('error_uniqueItems')

+                            });

+                            break;

+                        }

+                        seen[valid] = true;

+                    }

+                }

+            }

+            // Object specific validation

+            else if (typeof value === "object" && value !== null) {

+                // `maxProperties`

+                if (schema.maxProperties) {

+                    valid = 0;

+                    for (i in value) {

+                        if (!value.hasOwnProperty(i)) continue;

+                        valid++;

+                    }

+                    if (valid > schema.maxProperties) {

+                        errors.push({

+                            path: path,

+                            property: 'maxProperties',

+                            message: this.translate('error_maxProperties', [schema.maxProperties])

+                        });

+                    }

+                }

+

+                // `minProperties`

+                if (schema.minProperties) {

+                    valid = 0;

+                    for (i in value) {

+                        if (!value.hasOwnProperty(i)) continue;

+                        valid++;

+                    }

+                    if (valid < schema.minProperties) {

+                        errors.push({

+                            path: path,

+                            property: 'minProperties',

+                            message: this.translate('error_minProperties', [schema.minProperties])

+                        });

+                    }

+                }

+

+                // Version 4 `required`

+                if (schema.required && Array.isArray(schema.required)) {

+                    for (i = 0; i < schema.required.length; i++) {

+                        if (typeof value[schema.required[i]] === "undefined") {

+                            errors.push({

+                                path: path,

+                                property: 'required',

+                                message: this.translate('error_required', [schema.required[i]])

+                            });

+                        }

+                    }

+                }

+

+                // `properties`

+                var validated_properties = {};

+                if (schema.properties) {

+                    for (i in schema.properties) {

+                        if (!schema.properties.hasOwnProperty(i)) continue;

+                        validated_properties[i] = true;

+                        errors = errors.concat(this._validateSchema(schema.properties[i], value[i], path + '.' + i));

+                    }

+                }

+

+                // `patternProperties`

+                if (schema.patternProperties) {

+                    for (i in schema.patternProperties) {

+                        if (!schema.patternProperties.hasOwnProperty(i)) continue;

+

+                        var regex = new RegExp(i);

+

+                        // Check which properties match

+                        for (j in value) {

+                            if (!value.hasOwnProperty(j)) continue;

+                            if (regex.test(j)) {

+                                validated_properties[j] = true;

+                                errors = errors.concat(this._validateSchema(schema.patternProperties[i], value[j], path + '.' + j));

+                            }

+                        }

+                    }

+                }

+

+                // The no_additional_properties option currently doesn't work with extended schemas that use oneOf or anyOf

+                if (typeof schema.additionalProperties === "undefined" && this.jsoneditor.options.no_additional_properties && !schema.oneOf && !schema.anyOf) {

+                    schema.additionalProperties = false;

+                }

+

+                // `additionalProperties`

+                if (typeof schema.additionalProperties !== "undefined") {

+                    for (i in value) {

+                        if (!value.hasOwnProperty(i)) continue;

+                        if (!validated_properties[i]) {

+                            // No extra properties allowed

+                            if (!schema.additionalProperties) {

+                                errors.push({

+                                    path: path,

+                                    property: 'additionalProperties',

+                                    message: this.translate('error_additional_properties', [i])

+                                });

+                                break;

+                            }

+                            // Allowed

+                            else if (schema.additionalProperties === true) {

+                                break;

+                            }

+                            // Must match schema

+                            // TODO: incompatibility between version 3 and 4 of the spec

+                            else {

+                                errors = errors.concat(this._validateSchema(schema.additionalProperties, value[i], path + '.' + i));

+                            }

+                        }

+                    }

+                }

+

+                // `dependencies`

+                if (schema.dependencies) {

+                    for (i in schema.dependencies) {

+                        if (!schema.dependencies.hasOwnProperty(i)) continue;

+

+                        // Doesn't need to meet the dependency

+                        if (typeof value[i] === "undefined") continue;

+

+                        // Property dependency

+                        if (Array.isArray(schema.dependencies[i])) {

+                            for (j = 0; j < schema.dependencies[i].length; j++) {

+                                if (typeof value[schema.dependencies[i][j]] === "undefined") {

+                                    errors.push({

+                                        path: path,

+                                        property: 'dependencies',

+                                        message: this.translate('error_dependency', [schema.dependencies[i][j]])

+                                    });

+                                }

+                            }

+                        }

+                        // Schema dependency

+                        else {

+                            errors = errors.concat(this._validateSchema(schema.dependencies[i], value, path));

+                        }

+                    }

+                }

+            }

+

+            // Custom type validation (global)

+            $each(JSONEditor.defaults.custom_validators, function(i, validator) {

+                errors = errors.concat(validator.call(self, schema, value, path));

+            });

+            // Custom type validation (instance specific)

+            if (this.options.custom_validators) {

+                $each(this.options.custom_validators, function(i, validator) {

+                    errors = errors.concat(validator.call(self, schema, value, path));

+                });

+            }

+

+            return errors;

+        },

+        _checkType: function(type, value) {

+            // Simple types

+            if (typeof type === "string") {

+                if (type === "string") return typeof value === "string";

+                else if (type === "number") return typeof value === "number";

+                else if (type === "integer") return typeof value === "number" && value === Math.floor(value);

+                else if (type === "boolean") return typeof value === "boolean";

+                else if (type === "array") return Array.isArray(value);

+                else if (type === "object") return value !== null && !(Array.isArray(value)) && typeof value === "object";

+                else if (type === "null") return value === null;

+                else return true;

+            }

+            // Schema

+            else {

+                return !this._validateSchema(type, value).length;

+            }

+        }

+    });

+

+    /**

+     * All editors should extend from this class

+     */

+    JSONEditor.AbstractEditor = Class.extend({

+        onChildEditorChange: function(editor) {

+            this.onChange(true);

+        },

+        notify: function() {

+            this.jsoneditor.notifyWatchers(this.path);

+        },

+        change: function() {

+            if (this.parent) this.parent.onChildEditorChange(this);

+            else this.jsoneditor.onChange();

+        },

+        onChange: function(bubble) {

+            this.notify();

+            if (this.watch_listener) this.watch_listener();

+            if (bubble) this.change();

+        },

+        register: function() {

+            this.jsoneditor.registerEditor(this);

+            this.onChange();

+        },

+        unregister: function() {

+            if (!this.jsoneditor) return;

+            this.jsoneditor.unregisterEditor(this);

+        },

+        getNumColumns: function() {

+            return 12;

+        },

+        init: function(options) {

+            this.jsoneditor = options.jsoneditor;

+

+            this.theme = this.jsoneditor.theme;

+            this.template_engine = this.jsoneditor.template;

+            this.iconlib = this.jsoneditor.iconlib;

+

+            this.original_schema = options.schema;

+            this.schema = this.jsoneditor.expandSchema(this.original_schema);

+

+            this.options = $extend({}, (this.options || {}), (options.schema.options || {}), options);

+

+            if (!options.path && !this.schema.id) this.schema.id = 'root';

+            this.path = options.path || 'root';

+            this.formname = options.formname || this.path.replace(/\.([^.]+)/g, '[$1]');

+            if (this.jsoneditor.options.form_name_root) this.formname = this.formname.replace(/^root\[/, this.jsoneditor.options.form_name_root + '[');

+            this.key = this.path.split('.').pop();

+            this.parent = options.parent;

+

+            this.link_watchers = [];

+

+            if (options.container) this.setContainer(options.container);

+        },

+        setContainer: function(container) {

+            this.container = container;

+            if (this.schema.id) this.container.setAttribute('data-schemaid', this.schema.id);

+            if (this.schema.type && typeof this.schema.type === "string") this.container.setAttribute('data-schematype', this.schema.type);

+            this.container.setAttribute('data-schemapath', this.path);

+        },

+

+        preBuild: function() {

+

+        },

+        build: function() {

+

+        },

+        postBuild: function() {

+            this.setupWatchListeners();

+            this.addLinks();

+            this.setValue(this.getDefault(), true);

+            this.updateHeaderText();

+            this.register();

+            this.onWatchedFieldChange();

+        },

+

+        setupWatchListeners: function() {

+            var self = this;

+

+            // Watched fields

+            this.watched = {};

+            if (this.schema.vars) this.schema.watch = this.schema.vars;

+            this.watched_values = {};

+            this.watch_listener = function() {

+                if (self.refreshWatchedFieldValues()) {

+                    self.onWatchedFieldChange();

+                }

+            };

+

+            this.register();

+            if (this.schema.hasOwnProperty('watch')) {

+                var path, path_parts, first, root, adjusted_path;

+

+                for (var name in this.schema.watch) {

+                    if (!this.schema.watch.hasOwnProperty(name)) continue;

+                    path = this.schema.watch[name];

+

+                    if (Array.isArray(path)) {

+                        path_parts = [path[0]].concat(path[1].split('.'));

+                    } else {

+                        path_parts = path.split('.');

+                        if (!self.theme.closest(self.container, '[data-schemaid="' + path_parts[0] + '"]')) path_parts.unshift('#');

+                    }

+                    first = path_parts.shift();

+

+                    if (first === '#') first = self.jsoneditor.schema.id || 'root';

+

+                    // Find the root node for this template variable

+                    root = self.theme.closest(self.container, '[data-schemaid="' + first + '"]');

+                    if (!root) throw "Could not find ancestor node with id " + first;

+

+                    // Keep track of the root node and path for use when rendering the template

+                    adjusted_path = root.getAttribute('data-schemapath') + '.' + path_parts.join('.');

+

+                    self.jsoneditor.watch(adjusted_path, self.watch_listener);

+

+                    self.watched[name] = adjusted_path;

+                }

+            }

+

+            // Dynamic header

+            if (this.schema.headerTemplate) {

+                this.header_template = this.jsoneditor.compileTemplate(this.schema.headerTemplate, this.template_engine);

+            }

+        },

+

+        addLinks: function() {

+            // Add links

+            if (!this.no_link_holder) {

+                this.link_holder = this.theme.getLinksHolder();

+                this.container.appendChild(this.link_holder);

+                if (this.schema.links) {

+                    for (var i = 0; i < this.schema.links.length; i++) {

+                        this.addLink(this.getLink(this.schema.links[i]));

+                    }

+                }

+            }

+        },

+

+

+        getButton: function(text, icon, title) {

+            var btnClass = 'json-editor-btn-' + icon;

+            if (!this.iconlib) icon = null;

+            else icon = this.iconlib.getIcon(icon);

+

+            if (!icon && title) {

+                text = title;

+                title = null;

+            }

+

+            var btn = this.theme.getButton(text, icon, title);

+            btn.className += ' ' + btnClass + ' ';

+            return btn;

+        },

+        setButtonText: function(button, text, icon, title) {

+            if (!this.iconlib) icon = null;

+            else icon = this.iconlib.getIcon(icon);

+

+            if (!icon && title) {

+                text = title;

+                title = null;

+            }

+

+            return this.theme.setButtonText(button, text, icon, title);

+        },

+        addLink: function(link) {

+            if (this.link_holder) this.link_holder.appendChild(link);

+        },

+        getLink: function(data) {

+            var holder, link;

+

+            // Get mime type of the link

+            var mime = data.mediaType || 'application/javascript';

+            var type = mime.split('/')[0];

+

+            // Template to generate the link href

+            var href = this.jsoneditor.compileTemplate(data.href, this.template_engine);

+

+            // Image links

+            if (type === 'image') {

+                holder = this.theme.getBlockLinkHolder();

+                link = document.createElement('a');

+                link.setAttribute('target', '_blank');

+                var image = document.createElement('img');

+

+                this.theme.createImageLink(holder, link, image);

+

+                // When a watched field changes, update the url  

+                this.link_watchers.push(function(vars) {

+                    var url = href(vars);

+                    link.setAttribute('href', url);

+                    link.setAttribute('title', data.rel || url);

+                    image.setAttribute('src', url);

+                });

+            }

+            // Audio/Video links

+            else if (['audio', 'video'].indexOf(type) >= 0) {

+                holder = this.theme.getBlockLinkHolder();

+

+                link = this.theme.getBlockLink();

+                link.setAttribute('target', '_blank');

+

+                var media = document.createElement(type);

+                media.setAttribute('controls', 'controls');

+

+                this.theme.createMediaLink(holder, link, media);

+

+                // When a watched field changes, update the url  

+                this.link_watchers.push(function(vars) {

+                    var url = href(vars);

+                    link.setAttribute('href', url);

+                    link.textContent = data.rel || url;

+                    media.setAttribute('src', url);

+                });

+            }

+            // Text links

+            else {

+                holder = this.theme.getBlockLink();

+                holder.setAttribute('target', '_blank');

+                holder.textContent = data.rel;

+

+                // When a watched field changes, update the url  

+                this.link_watchers.push(function(vars) {

+                    var url = href(vars);

+                    holder.setAttribute('href', url);

+                    holder.textContent = data.rel || url;

+                });

+            }

+

+            return holder;

+        },

+        refreshWatchedFieldValues: function() {

+            if (!this.watched_values) return;

+            var watched = {};

+            var changed = false;

+            var self = this;

+

+            if (this.watched) {

+                var val, editor;

+                for (var name in this.watched) {

+                    if (!this.watched.hasOwnProperty(name)) continue;

+                    editor = self.jsoneditor.getEditor(this.watched[name]);

+                    val = editor ? editor.getValue() : null;

+                    if (self.watched_values[name] !== val) changed = true;

+                    watched[name] = val;

+                }

+            }

+

+            watched.self = this.getValue();

+            if (this.watched_values.self !== watched.self) changed = true;

+

+            this.watched_values = watched;

+

+            return changed;

+        },

+        getWatchedFieldValues: function() {

+            return this.watched_values;

+        },

+        updateHeaderText: function() {

+            if (this.header) {

+                // If the header has children, only update the text node's value

+                if (this.header.children.length) {

+                    for (var i = 0; i < this.header.childNodes.length; i++) {

+                        if (this.header.childNodes[i].nodeType === 3) {

+                            this.header.childNodes[i].nodeValue = this.getHeaderText();

+                            break;

+                        }

+                    }

+                }

+                // Otherwise, just update the entire node

+                else {

+                    this.header.textContent = this.getHeaderText();

+                }

+            }

+        },

+        getHeaderText: function(title_only) {

+            if (this.header_text) return this.header_text;

+            else if (title_only) return this.schema.title;

+            else return this.getTitle();

+        },

+        onWatchedFieldChange: function() {

+            var vars;

+            if (this.header_template) {

+                vars = $extend(this.getWatchedFieldValues(), {

+                    key: this.key,

+                    i: this.key,

+                    i0: (this.key * 1),

+                    i1: (this.key * 1 + 1),

+                    title: this.getTitle()

+                });

+                var header_text = this.header_template(vars);

+

+                if (header_text !== this.header_text) {

+                    this.header_text = header_text;

+                    this.updateHeaderText();

+                    this.notify();

+                    //this.fireChangeHeaderEvent();

+                }

+            }

+            if (this.link_watchers.length) {

+                vars = this.getWatchedFieldValues();

+                for (var i = 0; i < this.link_watchers.length; i++) {

+                    this.link_watchers[i](vars);

+                }

+            }

+        },

+        setValue: function(value) {

+            this.value = value;

+        },

+        getValue: function() {

+            return this.value;

+        },

+        refreshValue: function() {

+

+        },

+        getChildEditors: function() {

+            return false;

+        },

+        destroy: function() {

+            var self = this;

+            this.unregister(this);

+            $each(this.watched, function(name, adjusted_path) {

+                self.jsoneditor.unwatch(adjusted_path, self.watch_listener);

+            });

+            this.watched = null;

+            this.watched_values = null;

+            this.watch_listener = null;

+            this.header_text = null;

+            this.header_template = null;

+            this.value = null;

+            if (this.container && this.container.parentNode) this.container.parentNode.removeChild(this.container);

+            this.container = null;

+            this.jsoneditor = null;

+            this.schema = null;

+            this.path = null;

+            this.key = null;

+            this.parent = null;

+        },

+        getDefault: function() {

+            if (this.schema["default"]) return this.schema["default"];

+            if (this.schema["enum"]) return this.schema["enum"][0];

+

+            var type = this.schema.type || this.schema.oneOf;

+            if (type && Array.isArray(type)) type = type[0];

+            if (type && typeof type === "object") type = type.type;

+            if (type && Array.isArray(type)) type = type[0];

+

+            if (typeof type === "string") {

+                if (type === "number") return 0.0;

+                if (type === "boolean") return false;

+                if (type === "integer") return 0;

+                if (type === "string") return "";

+                if (type === "object") return {};

+                if (type === "array") return [];

+            }

+

+            return null;

+        },

+        getTitle: function() {

+            return this.schema.title || this.key;

+        },

+        enable: function() {

+            this.disabled = false;

+        },

+        disable: function() {

+            this.disabled = true;

+        },

+        isEnabled: function() {

+            return !this.disabled;

+        },

+        isRequired: function() {

+            if (typeof this.schema.required === "boolean") return this.schema.required;

+            else if (this.parent && this.parent.schema && Array.isArray(this.parent.schema.required)) return this.parent.schema.required.indexOf(this.key) > -1;

+            else if (this.jsoneditor.options.required_by_default) return true;

+            else return false;

+        },

+        getDisplayText: function(arr) {

+            var disp = [];

+            var used = {};

+

+            // Determine how many times each attribute name is used.

+            // This helps us pick the most distinct display text for the schemas.

+            $each(arr, function(i, el) {

+                if (el.title) {

+                    used[el.title] = used[el.title] || 0;

+                    used[el.title]++;

+                }

+                if (el.description) {

+                    used[el.description] = used[el.description] || 0;

+                    used[el.description]++;

+                }

+                if (el.format) {

+                    used[el.format] = used[el.format] || 0;

+                    used[el.format]++;

+                }

+                if (el.type) {

+                    used[el.type] = used[el.type] || 0;

+                    used[el.type]++;

+                }

+            });

+

+            // Determine display text for each element of the array

+            $each(arr, function(i, el) {

+                var name;

+

+                // If it's a simple string

+                if (typeof el === "string") name = el;

+                // Object

+                else if (el.title && used[el.title] <= 1) name = el.title;

+                else if (el.format && used[el.format] <= 1) name = el.format;

+                else if (el.type && used[el.type] <= 1) name = el.type;

+                else if (el.description && used[el.description] <= 1) name = el.descripton;

+                else if (el.title) name = el.title;

+                else if (el.format) name = el.format;

+                else if (el.type) name = el.type;

+                else if (el.description) name = el.description;

+                else if (JSON.stringify(el).length < 50) name = JSON.stringify(el);

+                else name = "type";

+

+                disp.push(name);

+            });

+

+            // Replace identical display text with "text 1", "text 2", etc.

+            var inc = {};

+            $each(disp, function(i, name) {

+                inc[name] = inc[name] || 0;

+                inc[name]++;

+

+                if (used[name] > 1) disp[i] = name + " " + inc[name];

+            });

+

+            return disp;

+        },

+        getOption: function(key) {

+            try {

+                throw "getOption is deprecated";

+            } catch (e) {

+                window.console.error(e);

+            }

+

+            return this.options[key];

+        },

+        showValidationErrors: function(errors) {

+

+        }

+    });

+

+    JSONEditor.defaults.editors["null"] = JSONEditor.AbstractEditor.extend({

+        getValue: function() {

+            return null;

+        },

+        setValue: function() {

+            this.onChange();

+        },

+        getNumColumns: function() {

+            return 2;

+        }

+    });

+

+    JSONEditor.defaults.editors.string = JSONEditor.AbstractEditor.extend({

+        register: function() {

+            this._super();

+            if (!this.input) return;

+            this.input.setAttribute('name', this.formname);

+        },

+        unregister: function() {

+            this._super();

+            if (!this.input) return;

+            this.input.removeAttribute('name');

+        },

+        setValue: function(value, initial, from_template) {

+            var self = this;

+

+            if (this.template && !from_template) {

+                return;

+            }

+

+            if (value === null || typeof value === 'undefined') value = "";

+            else if (typeof value === "object") value = JSON.stringify(value);

+            else if (typeof value !== "string") value = "" + value;

+

+            if (value === this.serialized) return;

+

+            // Sanitize value before setting it

+            var sanitized = this.sanitize(value);

+

+            if (this.input.value === sanitized) {

+                return;

+            }

+

+            this.input.value = sanitized;

+

+            // If using SCEditor, update the WYSIWYG

+            if (this.sceditor_instance) {

+                this.sceditor_instance.val(sanitized);

+            } else if (this.epiceditor) {

+                this.epiceditor.importFile(null, sanitized);

+            } else if (this.ace_editor) {

+                this.ace_editor.setValue(sanitized);

+            }

+

+            var changed = from_template || this.getValue() !== value;

+

+            this.refreshValue();

+

+            if (initial) this.is_dirty = false;

+            else if (this.jsoneditor.options.show_errors === "change") this.is_dirty = true;

+

+            if (this.adjust_height) this.adjust_height(this.input);

+

+            // Bubble this setValue to parents if the value changed

+            this.onChange(changed);

+        },

+        getNumColumns: function() {

+            var min = Math.ceil(Math.max(this.getTitle().length, this.schema.maxLength || 0, this.schema.minLength || 0) / 5);

+            var num;

+

+            if (this.input_type === 'textarea') num = 6;

+            else if (['text', 'email'].indexOf(this.input_type) >= 0) num = 4;

+            else num = 2;

+

+            return Math.min(12, Math.max(min, num));

+        },

+        build: function() {

+            var self = this,

+                i;

+            if (!this.options.compact) this.header = this.label = this.theme.getFormInputLabel(this.getTitle());

+            if (this.schema.description) this.description = this.theme.getFormInputDescription(this.schema.description);

+

+            this.format = this.schema.format;

+            if (!this.format && this.schema.media && this.schema.media.type) {

+                this.format = this.schema.media.type.replace(/(^(application|text)\/(x-)?(script\.)?)|(-source$)/g, '');

+            }

+            if (!this.format && this.options.default_format) {

+                this.format = this.options.default_format;

+            }

+            if (this.options.format) {

+                this.format = this.options.format;

+            }

+

+            // Specific format

+            if (this.format) {

+                // Text Area

+                if (this.format === 'textarea') {

+                    this.input_type = 'textarea';

+                    this.input = this.theme.getTextareaInput();

+                }

+                // Range Input

+                else if (this.format === 'range') {

+                    this.input_type = 'range';

+                    var min = this.schema.minimum || 0;

+                    var max = this.schema.maximum || Math.max(100, min + 1);

+                    var step = 1;

+                    if (this.schema.multipleOf) {

+                        if (min % this.schema.multipleOf) min = Math.ceil(min / this.schema.multipleOf) * this.schema.multipleOf;

+                        if (max % this.schema.multipleOf) max = Math.floor(max / this.schema.multipleOf) * this.schema.multipleOf;

+                        step = this.schema.multipleOf;

+                    }

+

+                    this.input = this.theme.getRangeInput(min, max, step);

+                }

+                // Source Code

+                else if ([

+                    'actionscript',

+                    'batchfile',

+                    'bbcode',

+                    'c',

+                    'c++',

+                    'cpp',

+                    'coffee',

+                    'csharp',

+                    'css',

+                    'dart',

+                    'django',

+                    'ejs',

+                    'erlang',

+                    'golang',

+                    'handlebars',

+                    'haskell',

+                    'haxe',

+                    'html',

+                    'ini',

+                    'jade',

+                    'java',

+                    'javascript',

+                    'json',

+                    'less',

+                    'lisp',

+                    'lua',

+                    'makefile',

+                    'markdown',

+                    'matlab',

+                    'mysql',

+                    'objectivec',

+                    'pascal',

+                    'perl',

+                    'pgsql',

+                    'php',

+                    'python',

+                    'r',

+                    'ruby',

+                    'sass',

+                    'scala',

+                    'scss',

+                    'smarty',

+                    'sql',

+                    'stylus',

+                    'svg',

+                    'twig',

+                    'vbscript',

+                    'xml',

+                    'yaml'

+                ].indexOf(this.format) >= 0) {

+                    this.input_type = this.format;

+                    this.source_code = true;

+

+                    this.input = this.theme.getTextareaInput();

+                }

+                // HTML5 Input type

+                else {

+                    this.input_type = this.format;

+                    this.input = this.theme.getFormInputField(this.input_type);

+                }

+            }

+            // Normal text input

+            else {

+                this.input_type = 'text';

+                this.input = this.theme.getFormInputField(this.input_type);

+            }

+

+            // minLength, maxLength, and pattern

+            if (typeof this.schema.maxLength !== "undefined") this.input.setAttribute('maxlength', this.schema.maxLength);

+            if (typeof this.schema.pattern !== "undefined") this.input.setAttribute('pattern', this.schema.pattern);

+            else if (typeof this.schema.minLength !== "undefined") this.input.setAttribute('pattern', '.{' + this.schema.minLength + ',}');

+

+            if (this.options.compact) {

+                this.container.className += ' compact';

+            } else {

+                if (this.options.input_width) this.input.style.width = this.options.input_width;

+            }

+

+            if (this.schema.readOnly || this.schema.readonly || this.schema.template) {

+                this.always_disabled = true;

+                this.input.disabled = true;

+            }

+

+            this.input

+                .addEventListener('change', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+

+                    // Don't allow changing if this field is a template

+                    if (self.schema.template) {

+                        this.value = self.value;

+                        return;

+                    }

+

+                    var val = this.value;

+

+                    // sanitize value

+                    var sanitized = self.sanitize(val);

+                    if (val !== sanitized) {

+                        this.value = sanitized;

+                    }

+

+                    self.is_dirty = true;

+

+                    self.refreshValue();

+                    self.onChange(true);

+                }, false);

+

+            if (this.options.input_height) this.input.style.height = this.options.input_height;

+            if (this.options.expand_height) {

+                this.adjust_height = function(el) {

+                    if (!el) return;

+                    var i, ch = el.offsetHeight;

+                    // Input too short

+                    if (el.offsetHeight < el.scrollHeight) {

+                        i = 0;

+                        while (el.offsetHeight < el.scrollHeight + 3) {

+                            if (i > 100) break;

+                            i++;

+                            ch++;

+                            el.style.height = ch + 'px';

+                        }

+                    } else {

+                        i = 0;

+                        while (el.offsetHeight >= el.scrollHeight + 3) {

+                            if (i > 100) break;

+                            i++;

+                            ch--;

+                            el.style.height = ch + 'px';

+                        }

+                        el.style.height = (ch + 1) + 'px';

+                    }

+                };

+

+                this.input.addEventListener('keyup', function(e) {

+                    self.adjust_height(this);

+                }, false);

+                this.input.addEventListener('change', function(e) {

+                    self.adjust_height(this);

+                }, false);

+                this.adjust_height();

+            }

+

+            if (this.format) this.input.setAttribute('data-schemaformat', this.format);

+

+            this.control = this.theme.getFormControl(this.label, this.input, this.description);

+            this.container.appendChild(this.control);

+

+            // Any special formatting that needs to happen after the input is added to the dom

+            window.requestAnimationFrame(function() {

+                // Skip in case the input is only a temporary editor,

+                // otherwise, in the case of an ace_editor creation,

+                // it will generate an error trying to append it to the missing parentNode

+                if (self.input.parentNode) self.afterInputReady();

+                if (self.adjust_height) self.adjust_height(self.input);

+            });

+

+            // Compile and store the template

+            if (this.schema.template) {

+                this.template = this.jsoneditor.compileTemplate(this.schema.template, this.template_engine);

+                this.refreshValue();

+            } else {

+                this.refreshValue();

+            }

+        },

+        enable: function() {

+            if (!this.always_disabled) {

+                this.input.disabled = false;

+                // TODO: WYSIWYG and Markdown editors

+            }

+            this._super();

+        },

+        disable: function() {

+            this.input.disabled = true;

+            // TODO: WYSIWYG and Markdown editors

+            this._super();

+        },

+        afterInputReady: function() {

+            var self = this,

+                options;

+

+            // Code editor

+            if (this.source_code) {

+                // WYSIWYG html and bbcode editor

+                if (this.options.wysiwyg && ['html', 'bbcode'].indexOf(this.input_type) >= 0 &&

+                    window.jQuery && window.jQuery.fn && window.jQuery.fn.sceditor

+                ) {

+                    options = $extend({}, {

+                        plugins: self.input_type === 'html' ? 'xhtml' : 'bbcode',

+                        emoticonsEnabled: false,

+                        width: '100%',

+                        height: 300

+                    }, JSONEditor.plugins.sceditor, self.options.sceditor_options || {});

+

+                    window.jQuery(self.input).sceditor(options);

+

+                    self.sceditor_instance = window.jQuery(self.input).sceditor('instance');

+

+                    self.sceditor_instance.blur(function() {

+                        // Get editor's value

+                        var val = window.jQuery("<div>" + self.sceditor_instance.val() + "</div>");

+                        // Remove sceditor spans/divs

+                        window.jQuery('#sceditor-start-marker,#sceditor-end-marker,.sceditor-nlf', val).remove();

+                        // Set the value and update

+                        self.input.value = val.html();

+                        self.value = self.input.value;

+                        self.is_dirty = true;

+                        self.onChange(true);

+                    });

+                }

+                // EpicEditor for markdown (if it's loaded)

+                else if (this.input_type === 'markdown' && window.EpicEditor) {

+                    this.epiceditor_container = document.createElement('div');

+                    this.input.parentNode.insertBefore(this.epiceditor_container, this.input);

+                    this.input.style.display = 'none';

+

+                    options = $extend({}, JSONEditor.plugins.epiceditor, {

+                        container: this.epiceditor_container,

+                        clientSideStorage: false

+                    });

+

+                    this.epiceditor = new window.EpicEditor(options).load();

+

+                    this.epiceditor.importFile(null, this.getValue());

+

+                    this.epiceditor.on('update', function() {

+                        var val = self.epiceditor.exportFile();

+                        self.input.value = val;

+                        self.value = val;

+                        self.is_dirty = true;

+                        self.onChange(true);

+                    });

+                }

+                // ACE editor for everything else

+                else if (window.ace) {

+                    var mode = this.input_type;

+                    // aliases for c/cpp

+                    if (mode === 'cpp' || mode === 'c++' || mode === 'c') {

+                        mode = 'c_cpp';

+                    }

+

+                    this.ace_container = document.createElement('div');

+                    this.ace_container.style.width = '100%';

+                    this.ace_container.style.position = 'relative';

+                    this.ace_container.style.height = '400px';

+                    this.input.parentNode.insertBefore(this.ace_container, this.input);

+                    this.input.style.display = 'none';

+                    this.ace_editor = window.ace.edit(this.ace_container);

+

+                    this.ace_editor.setValue(this.getValue());

+

+                    // The theme

+                    if (JSONEditor.plugins.ace.theme) this.ace_editor.setTheme('ace/theme/' + JSONEditor.plugins.ace.theme);

+                    // The mode

+                    mode = window.ace.require("ace/mode/" + mode);

+                    if (mode) this.ace_editor.getSession().setMode(new mode.Mode());

+

+                    // Listen for changes

+                    this.ace_editor.on('change', function() {

+                        var val = self.ace_editor.getValue();

+                        self.input.value = val;

+                        self.refreshValue();

+                        self.is_dirty = true;

+                        self.onChange(true);

+                    });

+                }

+            }

+

+            self.theme.afterInputReady(self.input);

+        },

+        refreshValue: function() {

+            this.value = this.input.value;

+            if (typeof this.value !== "string") this.value = '';

+            this.serialized = this.value;

+        },

+        destroy: function() {

+            // If using SCEditor, destroy the editor instance

+            if (this.sceditor_instance) {

+                this.sceditor_instance.destroy();

+            } else if (this.epiceditor) {

+                this.epiceditor.unload();

+            } else if (this.ace_editor) {

+                this.ace_editor.destroy();

+            }

+

+

+            this.template = null;

+            if (this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input);

+            if (this.label && this.label.parentNode) this.label.parentNode.removeChild(this.label);

+            if (this.description && this.description.parentNode) this.description.parentNode.removeChild(this.description);

+

+            this._super();

+        },

+        /**

+         * This is overridden in derivative editors

+         */

+        sanitize: function(value) {

+            return value;

+        },

+        /**

+         * Re-calculates the value if needed

+         */

+        onWatchedFieldChange: function() {

+            var self = this,

+                vars, j;

+

+            // If this editor needs to be rendered by a macro template

+            if (this.template) {

+                vars = this.getWatchedFieldValues();

+                this.setValue(this.template(vars), false, true);

+            }

+

+            this._super();

+        },

+        showValidationErrors: function(errors) {

+            var self = this;

+

+            if (this.jsoneditor.options.show_errors === "always") {} else if (!this.is_dirty && this.previous_error_setting === this.jsoneditor.options.show_errors) return;

+

+            this.previous_error_setting = this.jsoneditor.options.show_errors;

+

+            var messages = [];

+            $each(errors, function(i, error) {

+                if (error.path === self.path) {

+                    messages.push(error.message);

+                }

+            });

+

+            if (messages.length) {

+                this.theme.addInputError(this.input, messages.join('. ') + '.');

+            } else {

+                this.theme.removeInputError(this.input);

+            }

+        }

+    });

+

+    JSONEditor.defaults.editors.number = JSONEditor.defaults.editors.string.extend({

+        sanitize: function(value) {

+            return (value + "").replace(/[^0-9\.\-eE]/g, '');

+        },

+        getNumColumns: function() {

+            return 2;

+        },

+        getValue: function() {

+            return this.value * 1;

+        }

+    });

+

+    JSONEditor.defaults.editors.integer = JSONEditor.defaults.editors.number.extend({

+        sanitize: function(value) {

+            value = value + "";

+            return value.replace(/[^0-9\-]/g, '');

+        },

+        getNumColumns: function() {

+            return 2;

+        }

+    });

+

+    JSONEditor.defaults.editors.object = JSONEditor.AbstractEditor.extend({

+        getDefault: function() {

+            return $extend({}, this.schema["default"] || {});

+        },

+        getChildEditors: function() {

+            return this.editors;

+        },

+        register: function() {

+            this._super();

+            if (this.editors) {

+                for (var i in this.editors) {

+                    if (!this.editors.hasOwnProperty(i)) continue;

+                    this.editors[i].register();

+                }

+            }

+        },

+        unregister: function() {

+            this._super();

+            if (this.editors) {

+                for (var i in this.editors) {

+                    if (!this.editors.hasOwnProperty(i)) continue;

+                    this.editors[i].unregister();

+                }

+            }

+        },

+        getNumColumns: function() {

+            return Math.max(Math.min(12, this.maxwidth), 3);

+        },

+        enable: function() {

+            if (this.editjson_button) this.editjson_button.disabled = false;

+            if (this.addproperty_button) this.addproperty_button.disabled = false;

+

+            this._super();

+            if (this.editors) {

+                for (var i in this.editors) {

+                    if (!this.editors.hasOwnProperty(i)) continue;

+                    this.editors[i].enable();

+                }

+            }

+        },

+        disable: function() {

+            if (this.editjson_button) this.editjson_button.disabled = true;

+            if (this.addproperty_button) this.addproperty_button.disabled = true;

+            this.hideEditJSON();

+

+            this._super();

+            if (this.editors) {

+                for (var i in this.editors) {

+                    if (!this.editors.hasOwnProperty(i)) continue;

+                    this.editors[i].disable();

+                }

+            }

+        },

+        layoutEditors: function() {

+            var self = this,

+                i, j;

+

+            if (!this.row_container) return;

+

+            // Sort editors by propertyOrder

+            this.property_order = Object.keys(this.editors);

+            this.property_order = this.property_order.sort(function(a, b) {

+                var ordera = self.editors[a].schema.propertyOrder;

+                var orderb = self.editors[b].schema.propertyOrder;

+                if (typeof ordera !== "number") ordera = 1000;

+                if (typeof orderb !== "number") orderb = 1000;

+

+                return ordera - orderb;

+            });

+

+            var container;

+

+            if (this.format === 'grid') {

+                var rows = [];

+                $each(this.property_order, function(j, key) {

+                    var editor = self.editors[key];

+                    if (editor.property_removed) return;

+                    var found = false;

+                    var width = editor.options.hidden ? 0 : (editor.options.grid_columns || editor.getNumColumns());

+                    var height = editor.options.hidden ? 0 : editor.container.offsetHeight;

+                    // See if the editor will fit in any of the existing rows first

+                    for (var i = 0; i < rows.length; i++) {

+                        // If the editor will fit in the row horizontally

+                        if (rows[i].width + width <= 12) {

+                            // If the editor is close to the other elements in height

+                            // i.e. Don't put a really tall editor in an otherwise short row or vice versa

+                            if (!height || (rows[i].minh * 0.5 < height && rows[i].maxh * 2 > height)) {

+                                found = i;

+                            }

+                        }

+                    }

+

+                    // If there isn't a spot in any of the existing rows, start a new row

+                    if (found === false) {

+                        rows.push({

+                            width: 0,

+                            minh: 999999,

+                            maxh: 0,

+                            editors: []

+                        });

+                        found = rows.length - 1;

+                    }

+

+                    rows[found].editors.push({

+                        key: key,

+                        //editor: editor,

+                        width: width,

+                        height: height

+                    });

+                    rows[found].width += width;

+                    rows[found].minh = Math.min(rows[found].minh, height);

+                    rows[found].maxh = Math.max(rows[found].maxh, height);

+                });

+

+                // Make almost full rows width 12

+                // Do this by increasing all editors' sizes proprotionately

+                // Any left over space goes to the biggest editor

+                // Don't touch rows with a width of 6 or less

+                for (i = 0; i < rows.length; i++) {

+                    if (rows[i].width < 12) {

+                        var biggest = false;

+                        var new_width = 0;

+                        for (j = 0; j < rows[i].editors.length; j++) {

+                            if (biggest === false) biggest = j;

+                            else if (rows[i].editors[j].width > rows[i].editors[biggest].width) biggest = j;

+                            rows[i].editors[j].width *= 12 / rows[i].width;

+                            rows[i].editors[j].width = Math.floor(rows[i].editors[j].width);

+                            new_width += rows[i].editors[j].width;

+                        }

+                        if (new_width < 12) rows[i].editors[biggest].width += 12 - new_width;

+                        rows[i].width = 12;

+                    }

+                }

+

+                // layout hasn't changed

+                if (this.layout === JSON.stringify(rows)) return false;

+                this.layout = JSON.stringify(rows);

+

+                // Layout the form

+                container = document.createElement('div');

+                for (i = 0; i < rows.length; i++) {

+                    var row = this.theme.getGridRow();

+                    container.appendChild(row);

+                    for (j = 0; j < rows[i].editors.length; j++) {

+                        var key = rows[i].editors[j].key;

+                        var editor = this.editors[key];

+

+                        if (editor.options.hidden) editor.container.style.display = 'none';

+                        else this.theme.setGridColumnSize(editor.container, rows[i].editors[j].width);

+                        row.appendChild(editor.container);

+                    }

+                }

+            }

+            // Normal layout

+            else {

+                container = document.createElement('div');

+                $each(this.property_order, function(i, key) {

+                    var editor = self.editors[key];

+                    if (editor.property_removed) return;

+                    var row = self.theme.getGridRow();

+                    container.appendChild(row);

+

+                    if (editor.options.hidden) editor.container.style.display = 'none';

+                    else self.theme.setGridColumnSize(editor.container, 12);

+                    row.appendChild(editor.container);

+                });

+            }

+            this.row_container.innerHTML = '';

+            this.row_container.appendChild(container);

+        },

+        getPropertySchema: function(key) {

+            // Schema declared directly in properties

+            var schema = this.schema.properties[key] || {};

+            schema = $extend({}, schema);

+            var matched = this.schema.properties[key] ? true : false;

+

+            // Any matching patternProperties should be merged in

+            if (this.schema.patternProperties) {

+                for (var i in this.schema.patternProperties) {

+                    if (!this.schema.patternProperties.hasOwnProperty(i)) continue;

+                    var regex = new RegExp(i);

+                    if (regex.test(key)) {

+                        schema.allOf = schema.allOf || [];

+                        schema.allOf.push(this.schema.patternProperties[i]);

+                        matched = true;

+                    }

+                }

+            }

+

+            // Hasn't matched other rules, use additionalProperties schema

+            if (!matched && this.schema.additionalProperties && typeof this.schema.additionalProperties === "object") {

+                schema = $extend({}, this.schema.additionalProperties);

+            }

+

+            return schema;

+        },

+        preBuild: function() {

+            this._super();

+

+            this.editors = {};

+            this.cached_editors = {};

+            var self = this;

+

+            this.format = this.options.layout || this.options.object_layout || this.schema.format || this.jsoneditor.options.object_layout || 'normal';

+

+            this.schema.properties = this.schema.properties || {};

+

+            this.minwidth = 0;

+            this.maxwidth = 0;

+

+            // If the object should be rendered as a table row

+            if (this.options.table_row) {

+                $each(this.schema.properties, function(key, schema) {

+                    var editor = self.jsoneditor.getEditorClass(schema);

+                    self.editors[key] = self.jsoneditor.createEditor(editor, {

+                        jsoneditor: self.jsoneditor,

+                        schema: schema,

+                        path: self.path + '.' + key,

+                        parent: self,

+                        compact: true,

+                        required: true

+                    });

+                    self.editors[key].preBuild();

+

+                    var width = self.editors[key].options.hidden ? 0 : (self.editors[key].options.grid_columns || self.editors[key].getNumColumns());

+

+                    self.minwidth += width;

+                    self.maxwidth += width;

+                });

+                this.no_link_holder = true;

+            }

+            // If the object should be rendered as a table

+            else if (this.options.table) {

+                // TODO: table display format

+                throw "Not supported yet";

+            }

+            // If the object should be rendered as a div

+            else {

+                this.defaultProperties = this.schema.defaultProperties || Object.keys(this.schema.properties);

+

+                // Increase the grid width to account for padding

+                self.maxwidth += 1;

+

+                $each(this.defaultProperties, function(i, key) {

+                    self.addObjectProperty(key, true);

+

+                    if (self.editors[key]) {

+                        self.minwidth = Math.max(self.minwidth, (self.editors[key].options.grid_columns || self.editors[key].getNumColumns()));

+                        self.maxwidth += (self.editors[key].options.grid_columns || self.editors[key].getNumColumns());

+                    }

+                });

+            }

+

+            // Sort editors by propertyOrder

+            this.property_order = Object.keys(this.editors);

+            this.property_order = this.property_order.sort(function(a, b) {

+                var ordera = self.editors[a].schema.propertyOrder;

+                var orderb = self.editors[b].schema.propertyOrder;

+                if (typeof ordera !== "number") ordera = 1000;

+                if (typeof orderb !== "number") orderb = 1000;

+

+                return ordera - orderb;

+            });

+        },

+        build: function() {

+            var self = this;

+

+            // If the object should be rendered as a table row

+            if (this.options.table_row) {

+                this.editor_holder = this.container;

+                $each(this.editors, function(key, editor) {

+                    var holder = self.theme.getTableCell();

+                    self.editor_holder.appendChild(holder);

+

+                    editor.setContainer(holder);

+                    editor.build();

+                    editor.postBuild();

+

+                    if (self.editors[key].options.hidden) {

+                        holder.style.display = 'none';

+                    }

+                    if (self.editors[key].options.input_width) {

+                        holder.style.width = self.editors[key].options.input_width;

+                    }

+                });

+            }

+            // If the object should be rendered as a table

+            else if (this.options.table) {

+                // TODO: table display format

+                throw "Not supported yet";

+            }

+            // If the object should be rendered as a div

+            else {

+                this.header = document.createElement('span');

+                this.header.textContent = this.getTitle();

+                this.title = this.theme.getHeader(this.header);

+                this.container.appendChild(this.title);

+                this.container.style.position = 'relative';

+

+                // Edit JSON modal

+                this.editjson_holder = this.theme.getModal();

+                this.editjson_textarea = this.theme.getTextareaInput();

+                this.editjson_textarea.style.height = '170px';

+                this.editjson_textarea.style.width = '300px';

+                this.editjson_textarea.style.display = 'block';

+                this.editjson_save = this.getButton('Save', 'save', 'Save');

+                this.editjson_save.addEventListener('click', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+                    self.saveJSON();

+                }, false);

+                this.editjson_cancel = this.getButton('Cancel', 'cancel', 'Cancel');

+                this.editjson_cancel.addEventListener('click', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+                    self.hideEditJSON();

+                }, false);

+                this.editjson_holder.appendChild(this.editjson_textarea);

+                this.editjson_holder.appendChild(this.editjson_save);

+                this.editjson_holder.appendChild(this.editjson_cancel);

+

+                // Manage Properties modal

+                this.addproperty_holder = this.theme.getModal();

+                this.addproperty_list = document.createElement('div');

+                this.addproperty_list.style.width = '295px';

+                this.addproperty_list.style.maxHeight = '160px';

+                this.addproperty_list.style.padding = '5px 0';

+                this.addproperty_list.style.overflowY = 'auto';

+                this.addproperty_list.style.overflowX = 'hidden';

+                this.addproperty_list.style.paddingLeft = '5px';

+                this.addproperty_list.setAttribute('class', 'property-selector');

+                this.addproperty_add = this.getButton('add', 'add', 'add');

+                this.addproperty_input = this.theme.getFormInputField('text');

+                this.addproperty_input.setAttribute('placeholder', 'Property name...');

+                this.addproperty_input.style.width = '220px';

+                this.addproperty_input.style.marginBottom = '0';

+                this.addproperty_input.style.display = 'inline-block';

+                this.addproperty_add.addEventListener('click', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+                    if (self.addproperty_input.value) {

+                        if (self.editors[self.addproperty_input.value]) {

+                            window.alert('there is already a property with that name');

+                            return;

+                        }

+

+                        self.addObjectProperty(self.addproperty_input.value);

+                        if (self.editors[self.addproperty_input.value]) {

+                            self.editors[self.addproperty_input.value].disable();

+                        }

+                        self.onChange(true);

+                    }

+                }, false);

+                this.addproperty_holder.appendChild(this.addproperty_list);

+                this.addproperty_holder.appendChild(this.addproperty_input);

+                this.addproperty_holder.appendChild(this.addproperty_add);

+                var spacer = document.createElement('div');

+                spacer.style.clear = 'both';

+                this.addproperty_holder.appendChild(spacer);

+

+

+                // Description

+                if (this.schema.description) {

+                    this.description = this.theme.getDescription(this.schema.description);

+                    this.container.appendChild(this.description);

+                }

+

+                // Validation error placeholder area

+                this.error_holder = document.createElement('div');

+                this.container.appendChild(this.error_holder);

+

+                // Container for child editor area

+                this.editor_holder = this.theme.getIndentedPanel();

+                this.container.appendChild(this.editor_holder);

+

+                // Container for rows of child editors

+                this.row_container = this.theme.getGridContainer();

+                this.editor_holder.appendChild(this.row_container);

+

+                $each(this.editors, function(key, editor) {

+                    var holder = self.theme.getGridColumn();

+                    self.row_container.appendChild(holder);

+

+                    editor.setContainer(holder);

+                    editor.build();

+                    editor.postBuild();

+                });

+

+                // Control buttons

+                this.title_controls = this.theme.getHeaderButtonHolder();

+                this.editjson_controls = this.theme.getHeaderButtonHolder();

+                this.addproperty_controls = this.theme.getHeaderButtonHolder();

+                this.title.appendChild(this.title_controls);

+                this.title.appendChild(this.editjson_controls);

+                this.title.appendChild(this.addproperty_controls);

+

+                // Show/Hide button

+                this.collapsed = false;

+                this.toggle_button = this.getButton('', 'collapse', 'Collapse');

+                this.title_controls.appendChild(this.toggle_button);

+                this.toggle_button.addEventListener('click', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+                    if (self.collapsed) {

+                        self.editor_holder.style.display = '';

+                        self.collapsed = false;

+                        self.setButtonText(self.toggle_button, '', 'collapse', 'Collapse');

+                    } else {

+                        self.editor_holder.style.display = 'none';

+                        self.collapsed = true;

+                        self.setButtonText(self.toggle_button, '', 'expand', 'Expand');

+                    }

+                }, false);

+

+                // If it should start collapsed

+                if (this.options.collapsed) {

+                    $trigger(this.toggle_button, 'click');

+                }

+

+                // Collapse button disabled

+                if (this.schema.options && typeof this.schema.options.disable_collapse !== "undefined") {

+                    if (this.schema.options.disable_collapse) this.toggle_button.style.display = 'none';

+                } else if (this.jsoneditor.options.disable_collapse) {

+                    this.toggle_button.style.display = 'none';

+                }

+

+                // Edit JSON Button

+                this.editjson_button = this.getButton('JSON', 'edit', 'Edit JSON');

+                this.editjson_button.addEventListener('click', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+                    self.toggleEditJSON();

+                }, false);

+                this.editjson_controls.appendChild(this.editjson_button);

+                this.editjson_controls.appendChild(this.editjson_holder);

+

+                // Edit JSON Buttton disabled

+                if (this.schema.options && typeof this.schema.options.disable_edit_json !== "undefined") {

+                    if (this.schema.options.disable_edit_json) this.editjson_button.style.display = 'none';

+                } else if (this.jsoneditor.options.disable_edit_json) {

+                    this.editjson_button.style.display = 'none';

+                }

+

+                // Object Properties Button

+                this.addproperty_button = this.getButton('Properties', 'edit', 'Object Properties');

+                this.addproperty_button.addEventListener('click', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+                    self.toggleAddProperty();

+                }, false);

+                this.addproperty_controls.appendChild(this.addproperty_button);

+                this.addproperty_controls.appendChild(this.addproperty_holder);

+                this.refreshAddProperties();

+            }

+

+            // Fix table cell ordering

+            if (this.options.table_row) {

+                this.editor_holder = this.container;

+                $each(this.property_order, function(i, key) {

+                    self.editor_holder.appendChild(self.editors[key].container);

+                });

+            }

+            // Layout object editors in grid if needed

+            else {

+                // Initial layout

+                this.layoutEditors();

+                // Do it again now that we know the approximate heights of elements

+                this.layoutEditors();

+            }

+        },

+        showEditJSON: function() {

+            if (!this.editjson_holder) return;

+            this.hideAddProperty();

+

+            // Position the form directly beneath the button

+            // TODO: edge detection

+            this.editjson_holder.style.left = this.editjson_button.offsetLeft + "px";

+            this.editjson_holder.style.top = this.editjson_button.offsetTop + this.editjson_button.offsetHeight + "px";

+

+            // Start the textarea with the current value

+            this.editjson_textarea.value = JSON.stringify(this.getValue(), null, 2);

+

+            // Disable the rest of the form while editing JSON

+            this.disable();

+

+            this.editjson_holder.style.display = '';

+            this.editjson_button.disabled = false;

+            this.editing_json = true;

+        },

+        hideEditJSON: function() {

+            if (!this.editjson_holder) return;

+            if (!this.editing_json) return;

+

+            this.editjson_holder.style.display = 'none';

+            this.enable();

+            this.editing_json = false;

+        },

+        saveJSON: function() {

+            if (!this.editjson_holder) return;

+

+            try {

+                var json = JSON.parse(this.editjson_textarea.value);

+                this.setValue(json);

+                this.hideEditJSON();

+            } catch (e) {

+                window.alert('invalid JSON');

+                throw e;

+            }

+        },

+        toggleEditJSON: function() {

+            if (this.editing_json) this.hideEditJSON();

+            else this.showEditJSON();

+        },

+        insertPropertyControlUsingPropertyOrder: function(property, control, container) {

+            var propertyOrder;

+            if (this.schema.properties[property])

+                propertyOrder = this.schema.properties[property].propertyOrder;

+            if (typeof propertyOrder !== "number") propertyOrder = 1000;

+            control.propertyOrder = propertyOrder;

+

+            for (var i = 0; i < container.childNodes.length; i++) {

+                var child = container.childNodes[i];

+                if (control.propertyOrder < child.propertyOrder) {

+                    this.addproperty_list.insertBefore(control, child);

+                    control = null;

+                    break;

+                }

+            }

+            if (control) {

+                this.addproperty_list.appendChild(control);

+            }

+        },

+        addPropertyCheckbox: function(key) {

+            var self = this;

+            var checkbox, label, labelText, control;

+

+            checkbox = self.theme.getCheckbox();

+            checkbox.style.width = 'auto';

+

+            if (this.schema.properties[key] && this.schema.properties[key].title)

+                labelText = this.schema.properties[key].title;

+            else

+                labelText = key;

+

+            label = self.theme.getCheckboxLabel(labelText);

+

+            control = self.theme.getFormControl(label, checkbox);

+            control.style.paddingBottom = control.style.marginBottom = control.style.paddingTop = control.style.marginTop = 0;

+            control.style.height = 'auto';

+            //control.style.overflowY = 'hidden';

+

+            this.insertPropertyControlUsingPropertyOrder(key, control, this.addproperty_list);

+

+            checkbox.checked = key in this.editors;

+            checkbox.addEventListener('change', function() {

+                if (checkbox.checked) {

+                    self.addObjectProperty(key);

+                } else {

+                    self.removeObjectProperty(key);

+                }

+                self.onChange(true);

+            }, false);

+            self.addproperty_checkboxes[key] = checkbox;

+

+            return checkbox;

+        },

+        showAddProperty: function() {

+            if (!this.addproperty_holder) return;

+            this.hideEditJSON();

+

+            // Position the form directly beneath the button

+            // TODO: edge detection

+            this.addproperty_holder.style.left = this.addproperty_button.offsetLeft + "px";

+            this.addproperty_holder.style.top = this.addproperty_button.offsetTop + this.addproperty_button.offsetHeight + "px";

+

+            // Disable the rest of the form while editing JSON

+            this.disable();

+

+            this.adding_property = true;

+            this.addproperty_button.disabled = false;

+            this.addproperty_holder.style.display = '';

+            this.refreshAddProperties();

+        },

+        hideAddProperty: function() {

+            if (!this.addproperty_holder) return;

+            if (!this.adding_property) return;

+

+            this.addproperty_holder.style.display = 'none';

+            this.enable();

+

+            this.adding_property = false;

+        },

+        toggleAddProperty: function() {

+            if (this.adding_property) this.hideAddProperty();

+            else this.showAddProperty();

+        },

+        removeObjectProperty: function(property) {

+            if (this.editors[property]) {

+                this.editors[property].unregister();

+                delete this.editors[property];

+

+                this.refreshValue();

+                this.layoutEditors();

+            }

+        },

+        addObjectProperty: function(name, prebuild_only) {

+            var self = this;

+

+            // Property is already added

+            if (this.editors[name]) return;

+

+            // Property was added before and is cached

+            if (this.cached_editors[name]) {

+                this.editors[name] = this.cached_editors[name];

+                if (prebuild_only) return;

+                this.editors[name].register();

+            }

+            // New property

+            else {

+                if (!this.canHaveAdditionalProperties() && (!this.schema.properties || !this.schema.properties[name])) {

+                    return;

+                }

+

+                var schema = self.getPropertySchema(name);

+

+

+                // Add the property

+                var editor = self.jsoneditor.getEditorClass(schema);

+

+                self.editors[name] = self.jsoneditor.createEditor(editor, {

+                    jsoneditor: self.jsoneditor,

+                    schema: schema,

+                    path: self.path + '.' + name,

+                    parent: self

+                });

+                self.editors[name].preBuild();

+

+                if (!prebuild_only) {

+                    var holder = self.theme.getChildEditorHolder();

+                    self.editor_holder.appendChild(holder);

+                    self.editors[name].setContainer(holder);

+                    self.editors[name].build();

+                    self.editors[name].postBuild();

+                }

+

+                self.cached_editors[name] = self.editors[name];

+            }

+

+            // If we're only prebuilding the editors, don't refresh values

+            if (!prebuild_only) {

+                self.refreshValue();

+                self.layoutEditors();

+            }

+        },

+        onChildEditorChange: function(editor) {

+            this.refreshValue();

+            this._super(editor);

+        },

+        canHaveAdditionalProperties: function() {

+            if (typeof this.schema.additionalProperties === "boolean") {

+                return this.schema.additionalProperties;

+            }

+            return !this.jsoneditor.options.no_additional_properties;

+        },

+        destroy: function() {

+            $each(this.cached_editors, function(i, el) {

+                el.destroy();

+            });

+            if (this.editor_holder) this.editor_holder.innerHTML = '';

+            if (this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title);

+            if (this.error_holder && this.error_holder.parentNode) this.error_holder.parentNode.removeChild(this.error_holder);

+

+            this.editors = null;

+            this.cached_editors = null;

+            if (this.editor_holder && this.editor_holder.parentNode) this.editor_holder.parentNode.removeChild(this.editor_holder);

+            this.editor_holder = null;

+

+            this._super();

+        },

+        getValue: function() {

+            var result = this._super();

+            if (this.jsoneditor.options.remove_empty_properties || this.options.remove_empty_properties) {

+                for (var i in result) {

+                    if (result.hasOwnProperty(i)) {

+                        if (!result[i]) delete result[i];

+                    }

+                }

+            }

+            return result;

+        },

+        refreshValue: function() {

+            this.value = {};

+            var self = this;

+

+            for (var i in this.editors) {

+                if (!this.editors.hasOwnProperty(i)) continue;

+                this.value[i] = this.editors[i].getValue();

+            }

+

+            if (this.adding_property) this.refreshAddProperties();

+        },

+        refreshAddProperties: function() {

+            if (this.options.disable_properties || (this.options.disable_properties !== false && this.jsoneditor.options.disable_properties)) {

+                this.addproperty_controls.style.display = 'none';

+                return;

+            }

+

+            var can_add = false,

+                can_remove = false,

+                num_props = 0,

+                i, show_modal = false;

+

+            // Get number of editors

+            for (i in this.editors) {

+                if (!this.editors.hasOwnProperty(i)) continue;

+                num_props++;

+            }

+

+            // Determine if we can add back removed properties

+            can_add = this.canHaveAdditionalProperties() && !(typeof this.schema.maxProperties !== "undefined" && num_props >= this.schema.maxProperties);

+

+            if (this.addproperty_checkboxes) {

+                this.addproperty_list.innerHTML = '';

+            }

+            this.addproperty_checkboxes = {};

+

+            // Check for which editors can't be removed or added back

+            for (i in this.cached_editors) {

+                if (!this.cached_editors.hasOwnProperty(i)) continue;

+

+                this.addPropertyCheckbox(i);

+

+                if (this.isRequired(this.cached_editors[i]) && i in this.editors) {

+                    this.addproperty_checkboxes[i].disabled = true;

+                }

+

+                if (typeof this.schema.minProperties !== "undefined" && num_props <= this.schema.minProperties) {

+                    this.addproperty_checkboxes[i].disabled = this.addproperty_checkboxes[i].checked;

+                    if (!this.addproperty_checkboxes[i].checked) show_modal = true;

+                } else if (!(i in this.editors)) {

+                    if (!can_add && !this.schema.properties.hasOwnProperty(i)) {

+                        this.addproperty_checkboxes[i].disabled = true;

+                    } else {

+                        this.addproperty_checkboxes[i].disabled = false;

+                        show_modal = true;

+                    }

+                } else {

+                    show_modal = true;

+                    can_remove = true;

+                }

+            }

+

+            if (this.canHaveAdditionalProperties()) {

+                show_modal = true;

+            }

+

+            // Additional addproperty checkboxes not tied to a current editor

+            for (i in this.schema.properties) {

+                if (!this.schema.properties.hasOwnProperty(i)) continue;

+                if (this.cached_editors[i]) continue;

+                show_modal = true;

+                this.addPropertyCheckbox(i);

+            }

+

+            // If no editors can be added or removed, hide the modal button

+            if (!show_modal) {

+                this.hideAddProperty();

+                this.addproperty_controls.style.display = 'none';

+            }

+            // If additional properties are disabled

+            else if (!this.canHaveAdditionalProperties()) {

+                this.addproperty_add.style.display = 'none';

+                this.addproperty_input.style.display = 'none';

+            }

+            // If no new properties can be added

+            else if (!can_add) {

+                this.addproperty_add.disabled = true;

+            }

+            // If new properties can be added

+            else {

+                this.addproperty_add.disabled = false;

+            }

+        },

+        isRequired: function(editor) {

+            if (typeof editor.schema.required === "boolean") return editor.schema.required;

+            else if (Array.isArray(this.schema.required)) return this.schema.required.indexOf(editor.key) > -1;

+            else if (this.jsoneditor.options.required_by_default) return true;

+            else return false;

+        },

+        setValue: function(value, initial) {

+            var self = this;

+            value = value || {};

+

+            if (typeof value !== "object" || Array.isArray(value)) value = {};

+

+            // First, set the values for all of the defined properties

+            $each(this.cached_editors, function(i, editor) {

+                // Value explicitly set

+                if (typeof value[i] !== "undefined") {

+                    self.addObjectProperty(i);

+                    editor.setValue(value[i], initial);

+                }

+                // Otherwise, remove value unless this is the initial set or it's required

+                else if (!initial && !self.isRequired(editor)) {

+                    self.removeObjectProperty(i);

+                }

+                // Otherwise, set the value to the default

+                else {

+                    editor.setValue(editor.getDefault(), initial);

+                }

+            });

+

+            $each(value, function(i, val) {

+                if (!self.cached_editors[i]) {

+                    self.addObjectProperty(i);

+                    if (self.editors[i]) self.editors[i].setValue(val, initial);

+                }

+            });

+

+            this.refreshValue();

+            this.layoutEditors();

+            this.onChange();

+        },

+        showValidationErrors: function(errors) {

+            var self = this;

+

+            // Get all the errors that pertain to this editor

+            var my_errors = [];

+            var other_errors = [];

+            $each(errors, function(i, error) {

+                if (error.path === self.path) {

+                    my_errors.push(error);

+                } else {

+                    other_errors.push(error);

+                }

+            });

+

+            // Show errors for this editor

+            if (this.error_holder) {

+                if (my_errors.length) {

+                    var message = [];

+                    this.error_holder.innerHTML = '';

+                    this.error_holder.style.display = '';

+                    $each(my_errors, function(i, error) {

+                        self.error_holder.appendChild(self.theme.getErrorMessage(error.message));

+                    });

+                }

+                // Hide error area

+                else {

+                    this.error_holder.style.display = 'none';

+                }

+            }

+

+            // Show error for the table row if this is inside a table

+            if (this.options.table_row) {

+                if (my_errors.length) {

+                    this.theme.addTableRowError(this.container);

+                } else {

+                    this.theme.removeTableRowError(this.container);

+                }

+            }

+

+            // Show errors for child editors

+            $each(this.editors, function(i, editor) {

+                editor.showValidationErrors(other_errors);

+            });

+        }

+    });

+

+    JSONEditor.defaults.editors.array = JSONEditor.AbstractEditor.extend({

+        getDefault: function() {

+            return this.schema["default"] || [];

+        },

+        register: function() {

+            this._super();

+            if (this.rows) {

+                for (var i = 0; i < this.rows.length; i++) {

+                    this.rows[i].register();

+                }

+            }

+        },

+        unregister: function() {

+            this._super();

+            if (this.rows) {

+                for (var i = 0; i < this.rows.length; i++) {

+                    this.rows[i].unregister();

+                }

+            }

+        },

+        getNumColumns: function() {

+            var info = this.getItemInfo(0);

+            // Tabs require extra horizontal space

+            if (this.tabs_holder) {

+                return Math.max(Math.min(12, info.width + 2), 4);

+            } else {

+                return info.width;

+            }

+        },

+        enable: function() {

+            if (this.add_row_button) this.add_row_button.disabled = false;

+            if (this.remove_all_rows_button) this.remove_all_rows_button.disabled = false;

+            if (this.delete_last_row_button) this.delete_last_row_button.disabled = false;

+

+            if (this.rows) {

+                for (var i = 0; i < this.rows.length; i++) {

+                    this.rows[i].enable();

+

+                    if (this.rows[i].moveup_button) this.rows[i].moveup_button.disabled = false;

+                    if (this.rows[i].movedown_button) this.rows[i].movedown_button.disabled = false;

+                    if (this.rows[i].delete_button) this.rows[i].delete_button.disabled = false;

+                }

+            }

+            this._super();

+        },

+        disable: function() {

+            if (this.add_row_button) this.add_row_button.disabled = true;

+            if (this.remove_all_rows_button) this.remove_all_rows_button.disabled = true;

+            if (this.delete_last_row_button) this.delete_last_row_button.disabled = true;

+

+            if (this.rows) {

+                for (var i = 0; i < this.rows.length; i++) {

+                    this.rows[i].disable();

+

+                    if (this.rows[i].moveup_button) this.rows[i].moveup_button.disabled = true;

+                    if (this.rows[i].movedown_button) this.rows[i].movedown_button.disabled = true;

+                    if (this.rows[i].delete_button) this.rows[i].delete_button.disabled = true;

+                }

+            }

+            this._super();

+        },

+        preBuild: function() {

+            this._super();

+

+            this.rows = [];

+            this.row_cache = [];

+

+            this.hide_delete_buttons = this.options.disable_array_delete || this.jsoneditor.options.disable_array_delete;

+            this.hide_move_buttons = this.options.disable_array_reorder || this.jsoneditor.options.disable_array_reorder;

+            this.hide_add_button = this.options.disable_array_add || this.jsoneditor.options.disable_array_add;

+        },

+        build: function() {

+            var self = this;

+

+            if (!this.options.compact) {

+                this.header = document.createElement('span');

+                this.header.textContent = this.getTitle();

+                this.title = this.theme.getHeader(this.header);

+                this.container.appendChild(this.title);

+                this.title_controls = this.theme.getHeaderButtonHolder();

+                this.title.appendChild(this.title_controls);

+                if (this.schema.description) {

+                    this.description = this.theme.getDescription(this.schema.description);

+                    this.container.appendChild(this.description);

+                }

+                this.error_holder = document.createElement('div');

+                this.container.appendChild(this.error_holder);

+

+                if (this.schema.format === 'tabs') {

+                    this.controls = this.theme.getHeaderButtonHolder();

+                    this.title.appendChild(this.controls);

+                    this.tabs_holder = this.theme.getTabHolder();

+                    this.container.appendChild(this.tabs_holder);

+                    this.row_holder = this.theme.getTabContentHolder(this.tabs_holder);

+

+                    this.active_tab = null;

+                } else {

+                    this.panel = this.theme.getIndentedPanel();

+                    this.container.appendChild(this.panel);

+                    this.row_holder = document.createElement('div');

+                    this.panel.appendChild(this.row_holder);

+                    this.controls = this.theme.getButtonHolder();

+                    this.panel.appendChild(this.controls);

+                }

+            } else {

+                this.panel = this.theme.getIndentedPanel();

+                this.container.appendChild(this.panel);

+                this.controls = this.theme.getButtonHolder();

+                this.panel.appendChild(this.controls);

+                this.row_holder = document.createElement('div');

+                this.panel.appendChild(this.row_holder);

+            }

+

+            // Add controls

+            this.addControls();

+        },

+        onChildEditorChange: function(editor) {

+            this.refreshValue();

+            this.refreshTabs(true);

+            this._super(editor);

+        },

+        getItemTitle: function() {

+            if (!this.item_title) {

+                if (this.schema.items && !Array.isArray(this.schema.items)) {

+                    var tmp = this.jsoneditor.expandRefs(this.schema.items);

+                    this.item_title = tmp.title || 'item';

+                } else {

+                    this.item_title = 'item';

+                }

+            }

+            return this.item_title;

+        },

+        getItemSchema: function(i) {

+            if (Array.isArray(this.schema.items)) {

+                if (i >= this.schema.items.length) {

+                    if (this.schema.additionalItems === true) {

+                        return {};

+                    } else if (this.schema.additionalItems) {

+                        return $extend({}, this.schema.additionalItems);

+                    }

+                } else {

+                    return $extend({}, this.schema.items[i]);

+                }

+            } else if (this.schema.items) {

+                return $extend({}, this.schema.items);

+            } else {

+                return {};

+            }

+        },

+        getItemInfo: function(i) {

+            var schema = this.getItemSchema(i);

+

+            // Check if it's cached

+            this.item_info = this.item_info || {};

+            var stringified = JSON.stringify(schema);

+            if (typeof this.item_info[stringified] !== "undefined") return this.item_info[stringified];

+

+            // Get the schema for this item

+            schema = this.jsoneditor.expandRefs(schema);

+

+            this.item_info[stringified] = {

+                title: schema.title || "item",

+                'default': schema["default"],

+                width: 12,

+                child_editors: schema.properties || schema.items

+            };

+

+            return this.item_info[stringified];

+        },

+        getElementEditor: function(i) {

+            var item_info = this.getItemInfo(i);

+            var schema = this.getItemSchema(i);

+            schema = this.jsoneditor.expandRefs(schema);

+            schema.title = item_info.title + ' ' + (i + 1);

+

+            var editor = this.jsoneditor.getEditorClass(schema);

+

+            var holder;

+            if (this.tabs_holder) {

+                holder = this.theme.getTabContent();

+            } else if (item_info.child_editors) {

+                holder = this.theme.getChildEditorHolder();

+            } else {

+                holder = this.theme.getIndentedPanel();

+            }

+

+            this.row_holder.appendChild(holder);

+

+            var ret = this.jsoneditor.createEditor(editor, {

+                jsoneditor: this.jsoneditor,

+                schema: schema,

+                container: holder,

+                path: this.path + '.' + i,

+                parent: this,

+                required: true

+            });

+            ret.preBuild();

+            ret.build();

+            ret.postBuild();

+

+            if (!ret.title_controls) {

+                ret.array_controls = this.theme.getButtonHolder();

+                holder.appendChild(ret.array_controls);

+            }

+

+            return ret;

+        },

+        destroy: function() {

+            this.empty(true);

+            if (this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title);

+            if (this.description && this.description.parentNode) this.description.parentNode.removeChild(this.description);

+            if (this.row_holder && this.row_holder.parentNode) this.row_holder.parentNode.removeChild(this.row_holder);

+            if (this.controls && this.controls.parentNode) this.controls.parentNode.removeChild(this.controls);

+            if (this.panel && this.panel.parentNode) this.panel.parentNode.removeChild(this.panel);

+

+            this.rows = this.row_cache = this.title = this.description = this.row_holder = this.panel = this.controls = null;

+

+            this._super();

+        },

+        empty: function(hard) {

+            if (!this.rows) return;

+            var self = this;

+            $each(this.rows, function(i, row) {

+                if (hard) {

+                    if (row.tab && row.tab.parentNode) row.tab.parentNode.removeChild(row.tab);

+                    self.destroyRow(row, true);

+                    self.row_cache[i] = null;

+                }

+                self.rows[i] = null;

+            });

+            self.rows = [];

+            if (hard) self.row_cache = [];

+        },

+        destroyRow: function(row, hard) {

+            var holder = row.container;

+            if (hard) {

+                row.destroy();

+                if (holder.parentNode) holder.parentNode.removeChild(holder);

+                if (row.tab && row.tab.parentNode) row.tab.parentNode.removeChild(row.tab);

+            } else {

+                if (row.tab) row.tab.style.display = 'none';

+                holder.style.display = 'none';

+                row.unregister();

+            }

+        },

+        getMax: function() {

+            if ((Array.isArray(this.schema.items)) && this.schema.additionalItems === false) {

+                return Math.min(this.schema.items.length, this.schema.maxItems || Infinity);

+            } else {

+                return this.schema.maxItems || Infinity;

+            }

+        },

+        refreshTabs: function(refresh_headers) {

+            var self = this;

+            $each(this.rows, function(i, row) {

+                if (!row.tab) return;

+

+                if (refresh_headers) {

+                    row.tab_text.textContent = row.getHeaderText();

+                } else {

+                    if (row.tab === self.active_tab) {

+                        self.theme.markTabActive(row.tab);

+                        row.container.style.display = '';

+                    } else {

+                        self.theme.markTabInactive(row.tab);

+                        row.container.style.display = 'none';

+                    }

+                }

+            });

+        },

+        setValue: function(value, initial) {

+            // Update the array's value, adding/removing rows when necessary

+            value = value || [];

+

+            if (!(Array.isArray(value))) value = [value];

+

+            var serialized = JSON.stringify(value);

+            if (serialized === this.serialized) return;

+

+            // Make sure value has between minItems and maxItems items in it

+            if (this.schema.minItems) {

+                while (value.length < this.schema.minItems) {

+                    value.push(this.getItemInfo(value.length)["default"]);

+                }

+            }

+            if (this.getMax() && value.length > this.getMax()) {

+                value = value.slice(0, this.getMax());

+            }

+

+            var self = this;

+            $each(value, function(i, val) {

+                if (self.rows[i]) {

+                    // TODO: don't set the row's value if it hasn't changed

+                    self.rows[i].setValue(val, initial);

+                } else if (self.row_cache[i]) {

+                    self.rows[i] = self.row_cache[i];

+                    self.rows[i].setValue(val, initial);

+                    self.rows[i].container.style.display = '';

+                    if (self.rows[i].tab) self.rows[i].tab.style.display = '';

+                    self.rows[i].register();

+                } else {

+                    self.addRow(val, initial);

+                }

+            });

+

+            for (var j = value.length; j < self.rows.length; j++) {

+                self.destroyRow(self.rows[j]);

+                self.rows[j] = null;

+            }

+            self.rows = self.rows.slice(0, value.length);

+

+            // Set the active tab

+            var new_active_tab = null;

+            $each(self.rows, function(i, row) {

+                if (row.tab === self.active_tab) {

+                    new_active_tab = row.tab;

+                    return false;

+                }

+            });

+            if (!new_active_tab && self.rows.length) new_active_tab = self.rows[0].tab;

+

+            self.active_tab = new_active_tab;

+

+            self.refreshValue(initial);

+            self.refreshTabs(true);

+            self.refreshTabs();

+

+            self.onChange();

+

+            // TODO: sortable

+        },

+        refreshValue: function(force) {

+            var self = this;

+            var oldi = this.value ? this.value.length : 0;

+            this.value = [];

+

+            $each(this.rows, function(i, editor) {

+                // Get the value for this editor

+                self.value[i] = editor.getValue();

+            });

+

+            if (oldi !== this.value.length || force) {

+                // If we currently have minItems items in the array

+                var minItems = this.schema.minItems && this.schema.minItems >= this.rows.length;

+

+                $each(this.rows, function(i, editor) {

+                    // Hide the move down button for the last row

+                    if (editor.movedown_button) {

+                        if (i === self.rows.length - 1) {

+                            editor.movedown_button.style.display = 'none';

+                        } else {

+                            editor.movedown_button.style.display = '';

+                        }

+                    }

+

+                    // Hide the delete button if we have minItems items

+                    if (editor.delete_button) {

+                        if (minItems) {

+                            editor.delete_button.style.display = 'none';

+                        } else {

+                            editor.delete_button.style.display = '';

+                        }

+                    }

+

+                    // Get the value for this editor

+                    self.value[i] = editor.getValue();

+                });

+

+                var controls_needed = false;

+

+                if (!this.value.length) {

+                    this.delete_last_row_button.style.display = 'none';

+                    this.remove_all_rows_button.style.display = 'none';

+                } else if (this.value.length === 1) {

+                    this.remove_all_rows_button.style.display = 'none';

+

+                    // If there are minItems items in the array, hide the delete button beneath the rows

+                    if (minItems || this.hide_delete_buttons) {

+                        this.delete_last_row_button.style.display = 'none';

+                    } else {

+                        this.delete_last_row_button.style.display = '';

+                        controls_needed = true;

+                    }

+                } else {

+                    // If there are minItems items in the array, hide the delete button beneath the rows

+                    if (minItems || this.hide_delete_buttons) {

+                        this.delete_last_row_button.style.display = 'none';

+                        this.remove_all_rows_button.style.display = 'none';

+                    } else {

+                        this.delete_last_row_button.style.display = '';

+                        this.remove_all_rows_button.style.display = '';

+                        controls_needed = true;

+                    }

+                }

+

+                // If there are maxItems in the array, hide the add button beneath the rows

+                if ((this.getMax() && this.getMax() <= this.rows.length) || this.hide_add_button) {

+                    this.add_row_button.style.display = 'none';

+                } else {

+                    this.add_row_button.style.display = '';

+                    controls_needed = true;

+                }

+

+                if (!this.collapsed && controls_needed) {

+                    this.controls.style.display = 'inline-block';

+                } else {

+                    this.controls.style.display = 'none';

+                }

+            }

+        },

+        addRow: function(value, initial) {

+            var self = this;

+            var i = this.rows.length;

+

+            self.rows[i] = this.getElementEditor(i);

+            self.row_cache[i] = self.rows[i];

+

+            if (self.tabs_holder) {

+                self.rows[i].tab_text = document.createElement('span');

+                self.rows[i].tab_text.textContent = self.rows[i].getHeaderText();

+                self.rows[i].tab = self.theme.getTab(self.rows[i].tab_text);

+                self.rows[i].tab.addEventListener('click', function(e) {

+                    self.active_tab = self.rows[i].tab;

+                    self.refreshTabs();

+                    e.preventDefault();

+                    e.stopPropagation();

+                }, false);

+

+                self.theme.addTab(self.tabs_holder, self.rows[i].tab);

+            }

+

+            var controls_holder = self.rows[i].title_controls || self.rows[i].array_controls;

+

+            // Buttons to delete row, move row up, and move row down

+            if (!self.hide_delete_buttons) {

+                self.rows[i].delete_button = this.getButton(self.getItemTitle(), 'delete', 'Delete ' + self.getItemTitle());

+                self.rows[i].delete_button.className += ' delete';

+                self.rows[i].delete_button.setAttribute('data-i', i);

+                self.rows[i].delete_button.addEventListener('click', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+                    var i = this.getAttribute('data-i') * 1;

+

+                    var value = self.getValue();

+

+                    var newval = [];

+                    var new_active_tab = null;

+                    $each(value, function(j, row) {

+                        if (j === i) {

+                            // If the one we're deleting is the active tab

+                            if (self.rows[j].tab === self.active_tab) {

+                                // Make the next tab active if there is one

+                                // Note: the next tab is going to be the current tab after deletion

+                                if (self.rows[j + 1]) new_active_tab = self.rows[j].tab;

+                                // Otherwise, make the previous tab active if there is one

+                                else if (j) new_active_tab = self.rows[j - 1].tab;

+                            }

+

+                            return; // If this is the one we're deleting

+                        }

+                        newval.push(row);

+                    });

+                    self.setValue(newval);

+                    if (new_active_tab) {

+                        self.active_tab = new_active_tab;

+                        self.refreshTabs();

+                    }

+

+                    self.onChange(true);

+                }, false);

+

+                if (controls_holder) {

+                    controls_holder.appendChild(self.rows[i].delete_button);

+                }

+            }

+

+            if (i && !self.hide_move_buttons) {

+                self.rows[i].moveup_button = this.getButton('', 'moveup', 'Move up');

+                self.rows[i].moveup_button.className += ' moveup';

+                self.rows[i].moveup_button.setAttribute('data-i', i);

+                self.rows[i].moveup_button.addEventListener('click', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+                    var i = this.getAttribute('data-i') * 1;

+

+                    if (i <= 0) return;

+                    var rows = self.getValue();

+                    var tmp = rows[i - 1];

+                    rows[i - 1] = rows[i];

+                    rows[i] = tmp;

+

+                    self.setValue(rows);

+                    self.active_tab = self.rows[i - 1].tab;

+                    self.refreshTabs();

+

+                    self.onChange(true);

+                }, false);

+

+                if (controls_holder) {

+                    controls_holder.appendChild(self.rows[i].moveup_button);

+                }

+            }

+

+            if (!self.hide_move_buttons) {

+                self.rows[i].movedown_button = this.getButton('', 'movedown', 'Move down');

+                self.rows[i].movedown_button.className += ' movedown';

+                self.rows[i].movedown_button.setAttribute('data-i', i);

+                self.rows[i].movedown_button.addEventListener('click', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+                    var i = this.getAttribute('data-i') * 1;

+

+                    var rows = self.getValue();

+                    if (i >= rows.length - 1) return;

+                    var tmp = rows[i + 1];

+                    rows[i + 1] = rows[i];

+                    rows[i] = tmp;

+

+                    self.setValue(rows);

+                    self.active_tab = self.rows[i + 1].tab;

+                    self.refreshTabs();

+                    self.onChange(true);

+                }, false);

+

+                if (controls_holder) {

+                    controls_holder.appendChild(self.rows[i].movedown_button);

+                }

+            }

+

+            if (value) self.rows[i].setValue(value, initial);

+            self.refreshTabs();

+        },

+        addControls: function() {

+            var self = this;

+

+            this.collapsed = false;

+            this.toggle_button = this.getButton('', 'collapse', 'Collapse');

+            this.title_controls.appendChild(this.toggle_button);

+            var row_holder_display = self.row_holder.style.display;

+            var controls_display = self.controls.style.display;

+            this.toggle_button.addEventListener('click', function(e) {

+                e.preventDefault();

+                e.stopPropagation();

+                if (self.collapsed) {

+                    self.collapsed = false;

+                    if (self.panel) self.panel.style.display = '';

+                    self.row_holder.style.display = row_holder_display;

+                    if (self.tabs_holder) self.tabs_holder.style.display = '';

+                    self.controls.style.display = controls_display;

+                    self.setButtonText(this, '', 'collapse', 'Collapse');

+                } else {

+                    self.collapsed = true;

+                    self.row_holder.style.display = 'none';

+                    if (self.tabs_holder) self.tabs_holder.style.display = 'none';

+                    self.controls.style.display = 'none';

+                    if (self.panel) self.panel.style.display = 'none';

+                    self.setButtonText(this, '', 'expand', 'Expand');

+                }

+            }, false);

+

+            // If it should start collapsed

+            if (this.options.collapsed) {

+                $trigger(this.toggle_button, 'click');

+            }

+

+            // Collapse button disabled

+            if (this.schema.options && typeof this.schema.options.disable_collapse !== "undefined") {

+                if (this.schema.options.disable_collapse) this.toggle_button.style.display = 'none';

+            } else if (this.jsoneditor.options.disable_collapse) {

+                this.toggle_button.style.display = 'none';

+            }

+

+            // Add "new row" and "delete last" buttons below editor

+            this.add_row_button = this.getButton(this.getItemTitle(), 'add', 'Add ' + this.getItemTitle());

+

+            this.add_row_button.addEventListener('click', function(e) {

+                e.preventDefault();

+                e.stopPropagation();

+                var i = self.rows.length;

+                if (self.row_cache[i]) {

+                    self.rows[i] = self.row_cache[i];

+                    self.rows[i].setValue(self.rows[i].getDefault());

+                    self.rows[i].container.style.display = '';

+                    if (self.rows[i].tab) self.rows[i].tab.style.display = '';

+                    self.rows[i].register();

+                } else {

+                    self.addRow();

+                }

+                self.active_tab = self.rows[i].tab;

+                self.refreshTabs();

+                self.refreshValue();

+                self.onChange(true);

+            }, false);

+            self.controls.appendChild(this.add_row_button);

+

+            this.delete_last_row_button = this.getButton('Last ' + this.getItemTitle(), 'delete', 'Delete Last ' + this.getItemTitle());

+            this.delete_last_row_button.addEventListener('click', function(e) {

+                e.preventDefault();

+                e.stopPropagation();

+                var rows = self.getValue();

+

+                var new_active_tab = null;

+                if (self.rows.length > 1 && self.rows[self.rows.length - 1].tab === self.active_tab) new_active_tab = self.rows[self.rows.length - 2].tab;

+

+                rows.pop();

+                self.setValue(rows);

+                if (new_active_tab) {

+                    self.active_tab = new_active_tab;

+                    self.refreshTabs();

+                }

+                self.onChange(true);

+            }, false);

+            self.controls.appendChild(this.delete_last_row_button);

+

+            this.remove_all_rows_button = this.getButton('All', 'delete', 'Delete All');

+            this.remove_all_rows_button.addEventListener('click', function(e) {

+                e.preventDefault();

+                e.stopPropagation();

+                self.setValue([]);

+                self.onChange(true);

+            }, false);

+            self.controls.appendChild(this.remove_all_rows_button);

+

+            if (self.tabs) {

+                this.add_row_button.style.width = '100%';

+                this.add_row_button.style.textAlign = 'left';

+                this.add_row_button.style.marginBottom = '3px';

+

+                this.delete_last_row_button.style.width = '100%';

+                this.delete_last_row_button.style.textAlign = 'left';

+                this.delete_last_row_button.style.marginBottom = '3px';

+

+                this.remove_all_rows_button.style.width = '100%';

+                this.remove_all_rows_button.style.textAlign = 'left';

+                this.remove_all_rows_button.style.marginBottom = '3px';

+            }

+        },

+        showValidationErrors: function(errors) {

+            var self = this;

+

+            // Get all the errors that pertain to this editor

+            var my_errors = [];

+            var other_errors = [];

+            $each(errors, function(i, error) {

+                if (error.path === self.path) {

+                    my_errors.push(error);

+                } else {

+                    other_errors.push(error);

+                }

+            });

+

+            // Show errors for this editor

+            if (this.error_holder) {

+                if (my_errors.length) {

+                    var message = [];

+                    this.error_holder.innerHTML = '';

+                    this.error_holder.style.display = '';

+                    $each(my_errors, function(i, error) {

+                        self.error_holder.appendChild(self.theme.getErrorMessage(error.message));

+                    });

+                }

+                // Hide error area

+                else {

+                    this.error_holder.style.display = 'none';

+                }

+            }

+

+            // Show errors for child editors

+            $each(this.rows, function(i, row) {

+                row.showValidationErrors(other_errors);

+            });

+        }

+    });

+

+    JSONEditor.defaults.editors.table = JSONEditor.defaults.editors.array.extend({

+        register: function() {

+            this._super();

+            if (this.rows) {

+                for (var i = 0; i < this.rows.length; i++) {

+                    this.rows[i].register();

+                }

+            }

+        },

+        unregister: function() {

+            this._super();

+            if (this.rows) {

+                for (var i = 0; i < this.rows.length; i++) {

+                    this.rows[i].unregister();

+                }

+            }

+        },

+        getNumColumns: function() {

+            return Math.max(Math.min(12, this.width), 3);

+        },

+        preBuild: function() {

+            var item_schema = this.jsoneditor.expandRefs(this.schema.items || {});

+

+            this.item_title = item_schema.title || 'row';

+            this.item_default = item_schema["default"] || null;

+            this.item_has_child_editors = item_schema.properties || item_schema.items;

+            this.width = 12;

+            this._super();

+        },

+        build: function() {

+            var self = this;

+            this.table = this.theme.getTable();

+            this.container.appendChild(this.table);

+            this.thead = this.theme.getTableHead();

+            this.table.appendChild(this.thead);

+            this.header_row = this.theme.getTableRow();

+            this.thead.appendChild(this.header_row);

+            this.row_holder = this.theme.getTableBody();

+            this.table.appendChild(this.row_holder);

+

+            // Determine the default value of array element

+            var tmp = this.getElementEditor(0, true);

+            this.item_default = tmp.getDefault();

+            this.width = tmp.getNumColumns() + 2;

+

+            if (!this.options.compact) {

+                this.title = this.theme.getHeader(this.getTitle());

+                this.container.appendChild(this.title);

+                this.title_controls = this.theme.getHeaderButtonHolder();

+                this.title.appendChild(this.title_controls);

+                if (this.schema.description) {

+                    this.description = this.theme.getDescription(this.schema.description);

+                    this.container.appendChild(this.description);

+                }

+                this.panel = this.theme.getIndentedPanel();

+                this.container.appendChild(this.panel);

+                this.error_holder = document.createElement('div');

+                this.panel.appendChild(this.error_holder);

+            } else {

+                this.panel = document.createElement('div');

+                this.container.appendChild(this.panel);

+            }

+

+            this.panel.appendChild(this.table);

+            this.controls = this.theme.getButtonHolder();

+            this.panel.appendChild(this.controls);

+

+            if (this.item_has_child_editors) {

+                var ce = tmp.getChildEditors();

+                var order = tmp.property_order || Object.keys(ce);

+                for (var i = 0; i < order.length; i++) {

+                    var th = self.theme.getTableHeaderCell(ce[order[i]].getTitle());

+                    if (ce[order[i]].options.hidden) th.style.display = 'none';

+                    self.header_row.appendChild(th);

+                }

+            } else {

+                self.header_row.appendChild(self.theme.getTableHeaderCell(this.item_title));

+            }

+

+            tmp.destroy();

+            this.row_holder.innerHTML = '';

+

+            // Row Controls column

+            this.controls_header_cell = self.theme.getTableHeaderCell(" ");

+            self.header_row.appendChild(this.controls_header_cell);

+

+            // Add controls

+            this.addControls();

+        },

+        onChildEditorChange: function(editor) {

+            this.refreshValue();

+            this._super();

+        },

+        getItemDefault: function() {

+            return $extend({}, {

+                "default": this.item_default

+            })["default"];

+        },

+        getItemTitle: function() {

+            return this.item_title;

+        },

+        getElementEditor: function(i, ignore) {

+            var schema_copy = $extend({}, this.schema.items);

+            var editor = this.jsoneditor.getEditorClass(schema_copy, this.jsoneditor);

+            var row = this.row_holder.appendChild(this.theme.getTableRow());

+            var holder = row;

+            if (!this.item_has_child_editors) {

+                holder = this.theme.getTableCell();

+                row.appendChild(holder);

+            }

+

+            var ret = this.jsoneditor.createEditor(editor, {

+                jsoneditor: this.jsoneditor,

+                schema: schema_copy,

+                container: holder,

+                path: this.path + '.' + i,

+                parent: this,

+                compact: true,

+                table_row: true

+            });

+

+            ret.preBuild();

+            if (!ignore) {

+                ret.build();

+                ret.postBuild();

+

+                ret.controls_cell = row.appendChild(this.theme.getTableCell());

+                ret.row = row;

+                ret.table_controls = this.theme.getButtonHolder();

+                ret.controls_cell.appendChild(ret.table_controls);

+                ret.table_controls.style.margin = 0;

+                ret.table_controls.style.padding = 0;

+            }

+

+            return ret;

+        },

+        destroy: function() {

+            this.innerHTML = '';

+            if (this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title);

+            if (this.description && this.description.parentNode) this.description.parentNode.removeChild(this.description);

+            if (this.row_holder && this.row_holder.parentNode) this.row_holder.parentNode.removeChild(this.row_holder);

+            if (this.table && this.table.parentNode) this.table.parentNode.removeChild(this.table);

+            if (this.panel && this.panel.parentNode) this.panel.parentNode.removeChild(this.panel);

+

+            this.rows = this.title = this.description = this.row_holder = this.table = this.panel = null;

+

+            this._super();

+        },

+        setValue: function(value, initial) {

+            // Update the array's value, adding/removing rows when necessary

+            value = value || [];

+

+            // Make sure value has between minItems and maxItems items in it

+            if (this.schema.minItems) {

+                while (value.length < this.schema.minItems) {

+                    value.push(this.getItemDefault());

+                }

+            }

+            if (this.schema.maxItems && value.length > this.schema.maxItems) {

+                value = value.slice(0, this.schema.maxItems);

+            }

+

+            var serialized = JSON.stringify(value);

+            if (serialized === this.serialized) return;

+

+            var numrows_changed = false;

+

+            var self = this;

+            $each(value, function(i, val) {

+                if (self.rows[i]) {

+                    // TODO: don't set the row's value if it hasn't changed

+                    self.rows[i].setValue(val);

+                } else {

+                    self.addRow(val);

+                    numrows_changed = true;

+                }

+            });

+

+            for (var j = value.length; j < self.rows.length; j++) {

+                var holder = self.rows[j].container;

+                if (!self.item_has_child_editors) {

+                    self.rows[j].row.parentNode.removeChild(self.rows[j].row);

+                }

+                self.rows[j].destroy();

+                if (holder.parentNode) holder.parentNode.removeChild(holder);

+                self.rows[j] = null;

+                numrows_changed = true;

+            }

+            self.rows = self.rows.slice(0, value.length);

+

+            self.refreshValue();

+            if (numrows_changed || initial) self.refreshRowButtons();

+

+            self.onChange();

+

+            // TODO: sortable

+        },

+        refreshRowButtons: function() {

+            var self = this;

+

+            // If we currently have minItems items in the array

+            var minItems = this.schema.minItems && this.schema.minItems >= this.rows.length;

+

+            var need_row_buttons = false;

+            $each(this.rows, function(i, editor) {

+                // Hide the move down button for the last row

+                if (editor.movedown_button) {

+                    if (i === self.rows.length - 1) {

+                        editor.movedown_button.style.display = 'none';

+                    } else {

+                        need_row_buttons = true;

+                        editor.movedown_button.style.display = '';

+                    }

+                }

+

+                // Hide the delete button if we have minItems items

+                if (editor.delete_button) {

+                    if (minItems) {

+                        editor.delete_button.style.display = 'none';

+                    } else {

+                        need_row_buttons = true;

+                        editor.delete_button.style.display = '';

+                    }

+                }

+

+                if (editor.moveup_button) {

+                    need_row_buttons = true;

+                }

+            });

+

+            // Show/hide controls column in table

+            $each(this.rows, function(i, editor) {

+                if (need_row_buttons) {

+                    editor.controls_cell.style.display = '';

+                } else {

+                    editor.controls_cell.style.display = 'none';

+                }

+            });

+            if (need_row_buttons) {

+                this.controls_header_cell.style.display = '';

+            } else {

+                this.controls_header_cell.style.display = 'none';

+            }

+

+            var controls_needed = false;

+

+            if (!this.value.length) {

+                this.delete_last_row_button.style.display = 'none';

+                this.remove_all_rows_button.style.display = 'none';

+                this.table.style.display = 'none';

+            } else if (this.value.length === 1 || this.hide_delete_buttons) {

+                this.table.style.display = '';

+                this.remove_all_rows_button.style.display = 'none';

+

+                // If there are minItems items in the array, hide the delete button beneath the rows

+                if (minItems || this.hide_delete_buttons) {

+                    this.delete_last_row_button.style.display = 'none';

+                } else {

+                    this.delete_last_row_button.style.display = '';

+                    controls_needed = true;

+                }

+            } else {

+                this.table.style.display = '';

+                // If there are minItems items in the array, hide the delete button beneath the rows

+                if (minItems || this.hide_delete_buttons) {

+                    this.delete_last_row_button.style.display = 'none';

+                    this.remove_all_rows_button.style.display = 'none';

+                } else {

+                    this.delete_last_row_button.style.display = '';

+                    this.remove_all_rows_button.style.display = '';

+                    controls_needed = true;

+                }

+            }

+

+            // If there are maxItems in the array, hide the add button beneath the rows

+            if ((this.schema.maxItems && this.schema.maxItems <= this.rows.length) || this.hide_add_button) {

+                this.add_row_button.style.display = 'none';

+            } else {

+                this.add_row_button.style.display = '';

+                controls_needed = true;

+            }

+

+            if (!controls_needed) {

+                this.controls.style.display = 'none';

+            } else {

+                this.controls.style.display = '';

+            }

+        },

+        refreshValue: function() {

+            var self = this;

+            this.value = [];

+

+            $each(this.rows, function(i, editor) {

+                // Get the value for this editor

+                self.value[i] = editor.getValue();

+            });

+            this.serialized = JSON.stringify(this.value);

+        },

+        addRow: function(value) {

+            var self = this;

+            var i = this.rows.length;

+

+            self.rows[i] = this.getElementEditor(i);

+

+            var controls_holder = self.rows[i].table_controls;

+

+            // Buttons to delete row, move row up, and move row down

+            if (!this.hide_delete_buttons) {

+                self.rows[i].delete_button = this.getButton('', 'delete', 'Delete');

+                self.rows[i].delete_button.className += ' delete';

+                self.rows[i].delete_button.setAttribute('data-i', i);

+                self.rows[i].delete_button.addEventListener('click', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+                    var i = this.getAttribute('data-i') * 1;

+

+                    var value = self.getValue();

+

+                    var newval = [];

+                    $each(value, function(j, row) {

+                        if (j === i) return; // If this is the one we're deleting

+                        newval.push(row);

+                    });

+                    self.setValue(newval);

+                    self.onChange(true);

+                }, false);

+                controls_holder.appendChild(self.rows[i].delete_button);

+            }

+

+

+            if (i && !this.hide_move_buttons) {

+                self.rows[i].moveup_button = this.getButton('', 'moveup', 'Move up');

+                self.rows[i].moveup_button.className += ' moveup';

+                self.rows[i].moveup_button.setAttribute('data-i', i);

+                self.rows[i].moveup_button.addEventListener('click', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+                    var i = this.getAttribute('data-i') * 1;

+

+                    if (i <= 0) return;

+                    var rows = self.getValue();

+                    var tmp = rows[i - 1];

+                    rows[i - 1] = rows[i];

+                    rows[i] = tmp;

+

+                    self.setValue(rows);

+                    self.onChange(true);

+                }, false);

+                controls_holder.appendChild(self.rows[i].moveup_button);

+            }

+

+            if (!this.hide_move_buttons) {

+                self.rows[i].movedown_button = this.getButton('', 'movedown', 'Move down');

+                self.rows[i].movedown_button.className += ' movedown';

+                self.rows[i].movedown_button.setAttribute('data-i', i);

+                self.rows[i].movedown_button.addEventListener('click', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+                    var i = this.getAttribute('data-i') * 1;

+                    var rows = self.getValue();

+                    if (i >= rows.length - 1) return;

+                    var tmp = rows[i + 1];

+                    rows[i + 1] = rows[i];

+                    rows[i] = tmp;

+

+                    self.setValue(rows);

+                    self.onChange(true);

+                }, false);

+                controls_holder.appendChild(self.rows[i].movedown_button);

+            }

+

+            if (value) self.rows[i].setValue(value);

+        },

+        addControls: function() {

+            var self = this;

+

+            this.collapsed = false;

+            this.toggle_button = this.getButton('', 'collapse', 'Collapse');

+            if (this.title_controls) {

+                this.title_controls.appendChild(this.toggle_button);

+                this.toggle_button.addEventListener('click', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+

+                    if (self.collapsed) {

+                        self.collapsed = false;

+                        self.panel.style.display = '';

+                        self.setButtonText(this, '', 'collapse', 'Collapse');

+                    } else {

+                        self.collapsed = true;

+                        self.panel.style.display = 'none';

+                        self.setButtonText(this, '', 'expand', 'Expand');

+                    }

+                }, false);

+

+                // If it should start collapsed

+                if (this.options.collapsed) {

+                    $trigger(this.toggle_button, 'click');

+                }

+

+                // Collapse button disabled

+                if (this.schema.options && typeof this.schema.options.disable_collapse !== "undefined") {

+                    if (this.schema.options.disable_collapse) this.toggle_button.style.display = 'none';

+                } else if (this.jsoneditor.options.disable_collapse) {

+                    this.toggle_button.style.display = 'none';

+                }

+            }

+

+            // Add "new row" and "delete last" buttons below editor

+            this.add_row_button = this.getButton(this.getItemTitle(), 'add', 'Add ' + this.getItemTitle());

+            this.add_row_button.addEventListener('click', function(e) {

+                e.preventDefault();

+                e.stopPropagation();

+

+                self.addRow();

+                self.refreshValue();

+                self.refreshRowButtons();

+                self.onChange(true);

+            }, false);

+            self.controls.appendChild(this.add_row_button);

+

+            this.delete_last_row_button = this.getButton('Last ' + this.getItemTitle(), 'delete', 'Delete Last ' + this.getItemTitle());

+            this.delete_last_row_button.addEventListener('click', function(e) {

+                e.preventDefault();

+                e.stopPropagation();

+

+                var rows = self.getValue();

+                rows.pop();

+                self.setValue(rows);

+                self.onChange(true);

+            }, false);

+            self.controls.appendChild(this.delete_last_row_button);

+

+            this.remove_all_rows_button = this.getButton('All', 'delete', 'Delete All');

+            this.remove_all_rows_button.addEventListener('click', function(e) {

+                e.preventDefault();

+                e.stopPropagation();

+

+                self.setValue([]);

+                self.onChange(true);

+            }, false);

+            self.controls.appendChild(this.remove_all_rows_button);

+        }

+    });

+

+    // Multiple Editor (for when `type` is an array)

+    JSONEditor.defaults.editors.multiple = JSONEditor.AbstractEditor.extend({

+        register: function() {

+            if (this.editors) {

+                for (var i = 0; i < this.editors.length; i++) {

+                    if (!this.editors[i]) continue;

+                    this.editors[i].unregister();

+                }

+                if (this.editors[this.type]) this.editors[this.type].register();

+            }

+            this._super();

+        },

+        unregister: function() {

+            this._super();

+            if (this.editors) {

+                for (var i = 0; i < this.editors.length; i++) {

+                    if (!this.editors[i]) continue;

+                    this.editors[i].unregister();

+                }

+            }

+        },

+        getNumColumns: function() {

+            if (!this.editors[this.type]) return 4;

+            return Math.max(this.editors[this.type].getNumColumns(), 4);

+        },

+        enable: function() {

+            if (this.editors) {

+                for (var i = 0; i < this.editors.length; i++) {

+                    if (!this.editors[i]) continue;

+                    this.editors[i].enable();

+                }

+            }

+            this.switcher.disabled = false;

+            this._super();

+        },

+        disable: function() {

+            if (this.editors) {

+                for (var i = 0; i < this.editors.length; i++) {

+                    if (!this.editors[i]) continue;

+                    this.editors[i].disable();

+                }

+            }

+            this.switcher.disabled = true;

+            this._super();

+        },

+        switchEditor: function(i) {

+            var self = this;

+

+            if (!this.editors[i]) {

+                this.buildChildEditor(i);

+            }

+

+            self.type = i;

+

+            self.register();

+

+            var current_value = self.getValue();

+

+            $each(self.editors, function(type, editor) {

+                if (!editor) return;

+                if (self.type === type) {

+                    if (self.keep_values) editor.setValue(current_value, true);

+                    editor.container.style.display = '';

+                } else editor.container.style.display = 'none';

+            });

+            self.refreshValue();

+            self.refreshHeaderText();

+        },

+        buildChildEditor: function(i) {

+            var self = this;

+            var type = this.types[i];

+            var holder = self.theme.getChildEditorHolder();

+            self.editor_holder.appendChild(holder);

+

+            var schema;

+

+            if (typeof type === "string") {

+                schema = $extend({}, self.schema);

+                schema.type = type;

+            } else {

+                schema = $extend({}, self.schema, type);

+                schema = self.jsoneditor.expandRefs(schema);

+

+                // If we need to merge `required` arrays

+                if (type.required && Array.isArray(type.required) && self.schema.required && Array.isArray(self.schema.required)) {

+                    schema.required = self.schema.required.concat(type.required);

+                }

+            }

+

+            var editor = self.jsoneditor.getEditorClass(schema);

+

+            self.editors[i] = self.jsoneditor.createEditor(editor, {

+                jsoneditor: self.jsoneditor,

+                schema: schema,

+                container: holder,

+                path: self.path,

+                parent: self,

+                required: true

+            });

+            self.editors[i].preBuild();

+            self.editors[i].build();

+            self.editors[i].postBuild();

+

+            if (self.editors[i].header) self.editors[i].header.style.display = 'none';

+

+            self.editors[i].option = self.switcher_options[i];

+

+            holder.addEventListener('change_header_text', function() {

+                self.refreshHeaderText();

+            }, false);

+

+            if (i !== self.type) holder.style.display = 'none';

+        },

+        preBuild: function() {

+            var self = this;

+

+            this.types = [];

+            this.type = 0;

+            this.editors = [];

+            this.validators = [];

+

+            this.keep_values = true;

+            if (typeof this.jsoneditor.options.keep_oneof_values !== "undefined") this.keep_values = this.jsoneditor.options.keep_oneof_values;

+            if (typeof this.options.keep_oneof_values !== "undefined") this.keep_values = this.options.keep_oneof_values;

+

+            if (this.schema.oneOf) {

+                this.oneOf = true;

+                this.types = this.schema.oneOf;

+                $each(this.types, function(i, oneof) {

+                    //self.types[i] = self.jsoneditor.expandSchema(oneof);

+                });

+                delete this.schema.oneOf;

+            } else {

+                if (!this.schema.type || this.schema.type === "any") {

+                    this.types = ['string', 'number', 'integer', 'boolean', 'object', 'array', 'null'];

+

+                    // If any of these primitive types are disallowed

+                    if (this.schema.disallow) {

+                        var disallow = this.schema.disallow;

+                        if (typeof disallow !== 'object' || !(Array.isArray(disallow))) {

+                            disallow = [disallow];

+                        }

+                        var allowed_types = [];

+                        $each(this.types, function(i, type) {

+                            if (disallow.indexOf(type) === -1) allowed_types.push(type);

+                        });

+                        this.types = allowed_types;

+                    }

+                } else if (Array.isArray(this.schema.type)) {

+                    this.types = this.schema.type;

+                } else {

+                    this.types = [this.schema.type];

+                }

+                delete this.schema.type;

+            }

+

+            this.display_text = this.getDisplayText(this.types);

+        },

+        build: function() {

+            var self = this;

+            var container = this.container;

+

+            this.header = this.label = this.theme.getFormInputLabel(this.getTitle());

+            this.container.appendChild(this.header);

+

+            this.switcher = this.theme.getSwitcher(this.display_text);

+            container.appendChild(this.switcher);

+            this.switcher.addEventListener('change', function(e) {

+                e.preventDefault();

+                e.stopPropagation();

+

+                self.switchEditor(self.display_text.indexOf(this.value));

+                self.onChange(true);

+            }, false);

+

+            this.editor_holder = document.createElement('div');

+            container.appendChild(this.editor_holder);

+

+

+            var validator_options = {};

+            if (self.jsoneditor.options.custom_validators) {

+                validator_options.custom_validators = self.jsoneditor.options.custom_validators;

+            }

+

+            this.switcher_options = this.theme.getSwitcherOptions(this.switcher);

+            $each(this.types, function(i, type) {

+                self.editors[i] = false;

+

+                var schema;

+

+                if (typeof type === "string") {

+                    schema = $extend({}, self.schema);

+                    schema.type = type;

+                } else {

+                    schema = $extend({}, self.schema, type);

+

+                    // If we need to merge `required` arrays

+                    if (type.required && Array.isArray(type.required) && self.schema.required && Array.isArray(self.schema.required)) {

+                        schema.required = self.schema.required.concat(type.required);

+                    }

+                }

+

+                self.validators[i] = new JSONEditor.Validator(self.jsoneditor, schema, validator_options);

+            });

+

+            this.switchEditor(0);

+        },

+        onChildEditorChange: function(editor) {

+            if (this.editors[this.type]) {

+                this.refreshValue();

+                this.refreshHeaderText();

+            }

+

+            this._super();

+        },

+        refreshHeaderText: function() {

+            var display_text = this.getDisplayText(this.types);

+            $each(this.switcher_options, function(i, option) {

+                option.textContent = display_text[i];

+            });

+        },

+        refreshValue: function() {

+            this.value = this.editors[this.type].getValue();

+        },

+        setValue: function(val, initial) {

+            // Determine type by getting the first one that validates

+            var self = this;

+            $each(this.validators, function(i, validator) {

+                if (!validator.validate(val).length) {

+                    self.type = i;

+                    self.switcher.value = self.display_text[i];

+                    return false;

+                }

+            });

+

+            this.switchEditor(this.type);

+

+            this.editors[this.type].setValue(val, initial);

+

+            this.refreshValue();

+            self.onChange();

+        },

+        destroy: function() {

+            $each(this.editors, function(type, editor) {

+                if (editor) editor.destroy();

+            });

+            if (this.editor_holder && this.editor_holder.parentNode) this.editor_holder.parentNode.removeChild(this.editor_holder);

+            if (this.switcher && this.switcher.parentNode) this.switcher.parentNode.removeChild(this.switcher);

+            this._super();

+        },

+        showValidationErrors: function(errors) {

+            var self = this;

+

+            // oneOf error paths need to remove the oneOf[i] part before passing to child editors

+            if (this.oneOf) {

+                $each(this.editors, function(i, editor) {

+                    if (!editor) return;

+                    var check = self.path + '.oneOf[' + i + ']';

+                    var new_errors = [];

+                    $each(errors, function(j, error) {

+                        if (error.path.substr(0, check.length) === check) {

+                            var new_error = $extend({}, error);

+                            new_error.path = self.path + new_error.path.substr(check.length);

+                            new_errors.push(new_error);

+                        }

+                    });

+

+                    editor.showValidationErrors(new_errors);

+                });

+            } else {

+                $each(this.editors, function(type, editor) {

+                    if (!editor) return;

+                    editor.showValidationErrors(errors);

+                });

+            }

+        }

+    });

+

+    // Enum Editor (used for objects and arrays with enumerated values)

+    JSONEditor.defaults.editors["enum"] = JSONEditor.AbstractEditor.extend({

+        getNumColumns: function() {

+            return 4;

+        },

+        build: function() {

+            var container = this.container;

+            this.title = this.header = this.label = this.theme.getFormInputLabel(this.getTitle());

+            this.container.appendChild(this.title);

+

+            this.options.enum_titles = this.options.enum_titles || [];

+

+            this["enum"] = this.schema["enum"];

+            this.selected = 0;

+            this.select_options = [];

+            this.html_values = [];

+

+            var self = this;

+            for (var i = 0; i < this["enum"].length; i++) {

+                this.select_options[i] = this.options.enum_titles[i] || "Value " + (i + 1);

+                this.html_values[i] = this.getHTML(this["enum"][i]);

+            }

+

+            // Switcher

+            this.switcher = this.theme.getSwitcher(this.select_options);

+            this.container.appendChild(this.switcher);

+

+            // Display area

+            this.display_area = this.theme.getIndentedPanel();

+            this.container.appendChild(this.display_area);

+

+            if (this.options.hide_display) this.display_area.style.display = "none";

+

+            this.switcher.addEventListener('change', function() {

+                self.selected = self.select_options.indexOf(this.value);

+                self.value = self["enum"][self.selected];

+                self.refreshValue();

+                self.onChange(true);

+            }, false);

+            this.value = this["enum"][0];

+            this.refreshValue();

+

+            if (this["enum"].length === 1) this.switcher.style.display = 'none';

+        },

+        refreshValue: function() {

+            var self = this;

+            self.selected = -1;

+            var stringified = JSON.stringify(this.value);

+            $each(this["enum"], function(i, el) {

+                if (stringified === JSON.stringify(el)) {

+                    self.selected = i;

+                    return false;

+                }

+            });

+

+            if (self.selected < 0) {

+                self.setValue(self["enum"][0]);

+                return;

+            }

+

+            this.switcher.value = this.select_options[this.selected];

+            this.display_area.innerHTML = this.html_values[this.selected];

+        },

+        enable: function() {

+            if (!this.always_disabled) this.switcher.disabled = false;

+            this._super();

+        },

+        disable: function() {

+            this.switcher.disabled = true;

+            this._super();

+        },

+        getHTML: function(el) {

+            var self = this;

+

+            if (el === null) {

+                return '<em>null</em>';

+            }

+            // Array or Object

+            else if (typeof el === "object") {

+                // TODO: use theme

+                var ret = '';

+

+                $each(el, function(i, child) {

+                    var html = self.getHTML(child);

+

+                    // Add the keys to object children

+                    if (!(Array.isArray(el))) {

+                        // TODO: use theme

+                        html = '<div><em>' + i + '</em>: ' + html + '</div>';

+                    }

+

+                    // TODO: use theme

+                    ret += '<li>' + html + '</li>';

+                });

+

+                if (Array.isArray(el)) ret = '<ol>' + ret + '</ol>';

+                else ret = "<ul style='margin-top:0;margin-bottom:0;padding-top:0;padding-bottom:0;'>" + ret + '</ul>';

+

+                return ret;

+            }

+            // Boolean

+            else if (typeof el === "boolean") {

+                return el ? 'true' : 'false';

+            }

+            // String

+            else if (typeof el === "string") {

+                return el.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');

+            }

+            // Number

+            else {

+                return el;

+            }

+        },

+        setValue: function(val) {

+            if (this.value !== val) {

+                this.value = val;

+                this.refreshValue();

+                this.onChange();

+            }

+        },

+        destroy: function() {

+            if (this.display_area && this.display_area.parentNode) this.display_area.parentNode.removeChild(this.display_area);

+            if (this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title);

+            if (this.switcher && this.switcher.parentNode) this.switcher.parentNode.removeChild(this.switcher);

+

+            this._super();

+        }

+    });

+

+    JSONEditor.defaults.editors.select = JSONEditor.AbstractEditor.extend({

+        setValue: function(value, initial) {

+            value = this.typecast(value || '');

+

+            // Sanitize value before setting it

+            var sanitized = value;

+            if (this.enum_values.indexOf(sanitized) < 0) {

+                sanitized = this.enum_values[0];

+            }

+

+            if (this.value === sanitized) {

+                return;

+            }

+

+            this.input.value = this.enum_options[this.enum_values.indexOf(sanitized)];

+            if (this.select2) this.select2.select2('val', this.input.value);

+            this.value = sanitized;

+            this.onChange();

+        },

+        register: function() {

+            this._super();

+            if (!this.input) return;

+            this.input.setAttribute('name', this.formname);

+        },

+        unregister: function() {

+            this._super();

+            if (!this.input) return;

+            this.input.removeAttribute('name');

+        },

+        getNumColumns: function() {

+            if (!this.enum_options) return 3;

+            var longest_text = this.getTitle().length;

+            for (var i = 0; i < this.enum_options.length; i++) {

+                longest_text = Math.max(longest_text, this.enum_options[i].length + 4);

+            }

+            return Math.min(12, Math.max(longest_text / 7, 2));

+        },

+        typecast: function(value) {

+            if (this.schema.type === "boolean") {

+                return !!value;

+            } else if (this.schema.type === "number") {

+                return 1 * value;

+            } else if (this.schema.type === "integer") {

+                return Math.floor(value * 1);

+            } else {

+                return "" + value;

+            }

+        },

+        getValue: function() {

+            return this.value;

+        },

+        preBuild: function() {

+            var self = this;

+            this.input_type = 'select';

+            this.enum_options = [];

+            this.enum_values = [];

+            this.enum_display = [];

+

+            // Enum options enumerated

+            if (this.schema["enum"]) {

+                var display = this.schema.options && this.schema.options.enum_titles || [];

+

+                $each(this.schema["enum"], function(i, option) {

+                    self.enum_options[i] = "" + option;

+                    self.enum_display[i] = "" + (display[i] || option);

+                    self.enum_values[i] = self.typecast(option);

+                });

+

+                if (!this.isRequired()) {

+                    self.enum_display.unshift(' ');

+                    self.enum_options.unshift('undefined');

+                    self.enum_values.unshift(undefined);

+                }

+

+            }

+            // Boolean

+            else if (this.schema.type === "boolean") {

+                self.enum_display = this.schema.options && this.schema.options.enum_titles || ['true', 'false'];

+                self.enum_options = ['1', ''];

+                self.enum_values = [true, false];

+

+                if (!this.isRequired()) {

+                    self.enum_display.unshift(' ');

+                    self.enum_options.unshift('undefined');

+                    self.enum_values.unshift(undefined);

+                }

+

+            }

+            // Dynamic Enum

+            else if (this.schema.enumSource) {

+                this.enumSource = [];

+                this.enum_display = [];

+                this.enum_options = [];

+                this.enum_values = [];

+

+                // Shortcut declaration for using a single array

+                if (!(Array.isArray(this.schema.enumSource))) {

+                    if (this.schema.enumValue) {

+                        this.enumSource = [{

+                            source: this.schema.enumSource,

+                            value: this.schema.enumValue

+                        }];

+                    } else {

+                        this.enumSource = [{

+                            source: this.schema.enumSource

+                        }];

+                    }

+                } else {

+                    for (i = 0; i < this.schema.enumSource.length; i++) {

+                        // Shorthand for watched variable

+                        if (typeof this.schema.enumSource[i] === "string") {

+                            this.enumSource[i] = {

+                                source: this.schema.enumSource[i]

+                            };

+                        }

+                        // Make a copy of the schema

+                        else if (!(Array.isArray(this.schema.enumSource[i]))) {

+                            this.enumSource[i] = $extend({}, this.schema.enumSource[i]);

+                        } else {

+                            this.enumSource[i] = this.schema.enumSource[i];

+                        }

+                    }

+                }

+

+                // Now, enumSource is an array of sources

+                // Walk through this array and fix up the values

+                for (i = 0; i < this.enumSource.length; i++) {

+                    if (this.enumSource[i].value) {

+                        this.enumSource[i].value = this.jsoneditor.compileTemplate(this.enumSource[i].value, this.template_engine);

+                    }

+                    if (this.enumSource[i].title) {

+                        this.enumSource[i].title = this.jsoneditor.compileTemplate(this.enumSource[i].title, this.template_engine);

+                    }

+                    if (this.enumSource[i].filter) {

+                        this.enumSource[i].filter = this.jsoneditor.compileTemplate(this.enumSource[i].filter, this.template_engine);

+                    }

+                }

+            }

+            // Other, not supported

+            else {

+                throw "'select' editor requires the enum property to be set.";

+            }

+        },

+        build: function() {

+            var self = this;

+            if (!this.options.compact) this.header = this.label = this.theme.getFormInputLabel(this.getTitle());

+            if (this.schema.description) this.description = this.theme.getFormInputDescription(this.schema.description);

+

+            if (this.options.compact) this.container.className += ' compact';

+

+            this.input = this.theme.getSelectInput(this.enum_options);

+            this.theme.setSelectOptions(this.input, this.enum_options, this.enum_display);

+

+            if (this.schema.readOnly || this.schema.readonly) {

+                this.always_disabled = true;

+                this.input.disabled = true;

+            }

+

+            this.input.addEventListener('change', function(e) {

+                e.preventDefault();

+                e.stopPropagation();

+                self.onInputChange();

+            }, false);

+

+            this.control = this.theme.getFormControl(this.label, this.input, this.description);

+            this.container.appendChild(this.control);

+

+            this.value = this.enum_values[0];

+        },

+        onInputChange: function() {

+            var val = this.input.value;

+

+            var new_val;

+            // Invalid option, use first option instead

+            if (this.enum_options.indexOf(val) === -1) {

+                new_val = this.enum_values[0];

+            } else {

+                new_val = this.enum_values[this.enum_options.indexOf(val)];

+            }

+

+            // If valid hasn't changed

+            if (new_val === this.value) return;

+

+            // Store new value and propogate change event

+            this.value = new_val;

+            this.onChange(true);

+        },

+        setupSelect2: function() {

+            // If the Select2 library is loaded use it when we have lots of items

+            if (window.jQuery && window.jQuery.fn && window.jQuery.fn.select2 && (this.enum_options.length > 2 || (this.enum_options.length && this.enumSource))) {

+                var options = $extend({}, JSONEditor.plugins.select2);

+                if (this.schema.options && this.schema.options.select2_options) options = $extend(options, this.schema.options.select2_options);

+                this.select2 = window.jQuery(this.input).select2(options);

+                var self = this;

+                this.select2.on('select2-blur', function() {

+                    self.input.value = self.select2.select2('val');

+                    self.onInputChange();

+                });

+                this.select2.on('change', function() {

+                    self.input.value = self.select2.select2('val');

+                    self.onInputChange();

+                });

+            } else {

+                this.select2 = null;

+            }

+        },

+        postBuild: function() {

+            this._super();

+            this.theme.afterInputReady(this.input);

+            this.setupSelect2();

+        },

+        onWatchedFieldChange: function() {

+            var self = this,

+                vars, j;

+

+            // If this editor uses a dynamic select box

+            if (this.enumSource) {

+                vars = this.getWatchedFieldValues();

+                var select_options = [];

+                var select_titles = [];

+

+                for (var i = 0; i < this.enumSource.length; i++) {

+                    // Constant values

+                    if (Array.isArray(this.enumSource[i])) {

+                        select_options = select_options.concat(this.enumSource[i]);

+                        select_titles = select_titles.concat(this.enumSource[i]);

+                    } else {

+                        var items = [];

+                        // Static list of items

+                        if (Array.isArray(this.enumSource[i].source)) {

+                            items = this.enumSource[i].source;

+                            // A watched field

+                        } else {

+                            items = vars[this.enumSource[i].source];

+                        }

+

+                        if (items) {

+                            // Only use a predefined part of the array

+                            if (this.enumSource[i].slice) {

+                                items = Array.prototype.slice.apply(items, this.enumSource[i].slice);

+                            }

+                            // Filter the items

+                            if (this.enumSource[i].filter) {

+                                var new_items = [];

+                                for (j = 0; j < items.length; j++) {

+                                    if (this.enumSource[i].filter({

+                                        i: j,

+                                        item: items[j],

+                                        watched: vars

+                                    })) new_items.push(items[j]);

+                                }

+                                items = new_items;

+                            }

+

+                            var item_titles = [];

+                            var item_values = [];

+                            for (j = 0; j < items.length; j++) {

+                                var item = items[j];

+

+                                // Rendered value

+                                if (this.enumSource[i].value) {

+                                    item_values[j] = this.enumSource[i].value({

+                                        i: j,

+                                        item: item

+                                    });

+                                }

+                                // Use value directly

+                                else {

+                                    item_values[j] = items[j];

+                                }

+

+                                // Rendered title

+                                if (this.enumSource[i].title) {

+                                    item_titles[j] = this.enumSource[i].title({

+                                        i: j,

+                                        item: item

+                                    });

+                                }

+                                // Use value as the title also

+                                else {

+                                    item_titles[j] = item_values[j];

+                                }

+                            }

+

+                            // TODO: sort

+

+                            select_options = select_options.concat(item_values);

+                            select_titles = select_titles.concat(item_titles);

+                        }

+                    }

+                }

+

+                var prev_value = this.value;

+

+                this.theme.setSelectOptions(this.input, select_options, select_titles);

+                this.enum_options = select_options;

+                this.enum_display = select_titles;

+                this.enum_values = select_options;

+

+                if (this.select2) {

+                    this.select2.select2('destroy');

+                }

+

+                // If the previous value is still in the new select options, stick with it

+                if (select_options.indexOf(prev_value) !== -1) {

+                    this.input.value = prev_value;

+                    this.value = prev_value;

+                }

+                // Otherwise, set the value to the first select option

+                else {

+                    this.input.value = select_options[0];

+                    this.value = select_options[0] || "";

+                    if (this.parent) this.parent.onChildEditorChange(this);

+                    else this.jsoneditor.onChange();

+                    this.jsoneditor.notifyWatchers(this.path);

+                }

+

+                this.setupSelect2();

+            }

+

+            this._super();

+        },

+        enable: function() {

+            if (!this.always_disabled) {

+                this.input.disabled = false;

+                if (this.select2) this.select2.select2("enable", true);

+            }

+            this._super();

+        },

+        disable: function() {

+            this.input.disabled = true;

+            if (this.select2) this.select2.select2("enable", false);

+            this._super();

+        },

+        destroy: function() {

+            if (this.label && this.label.parentNode) this.label.parentNode.removeChild(this.label);

+            if (this.description && this.description.parentNode) this.description.parentNode.removeChild(this.description);

+            if (this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input);

+            if (this.select2) {

+                this.select2.select2('destroy');

+                this.select2 = null;

+            }

+

+            this._super();

+        }

+    });

+

+    JSONEditor.defaults.editors.selectize = JSONEditor.AbstractEditor.extend({

+        setValue: function(value, initial) {

+            value = this.typecast(value || '');

+

+            // Sanitize value before setting it

+            var sanitized = value;

+            if (this.enum_values.indexOf(sanitized) < 0) {

+                sanitized = this.enum_values[0];

+            }

+

+            if (this.value === sanitized) {

+                return;

+            }

+

+            this.input.value = this.enum_options[this.enum_values.indexOf(sanitized)];

+

+            if (this.selectize) {

+                this.selectize[0].selectize.addItem(sanitized);

+            }

+

+            this.value = sanitized;

+            this.onChange();

+        },

+        register: function() {

+            this._super();

+            if (!this.input) return;

+            this.input.setAttribute('name', this.formname);

+        },

+        unregister: function() {

+            this._super();

+            if (!this.input) return;

+            this.input.removeAttribute('name');

+        },

+        getNumColumns: function() {

+            if (!this.enum_options) return 3;

+            var longest_text = this.getTitle().length;

+            for (var i = 0; i < this.enum_options.length; i++) {

+                longest_text = Math.max(longest_text, this.enum_options[i].length + 4);

+            }

+            return Math.min(12, Math.max(longest_text / 7, 2));

+        },

+        typecast: function(value) {

+            if (this.schema.type === "boolean") {

+                return !!value;

+            } else if (this.schema.type === "number") {

+                return 1 * value;

+            } else if (this.schema.type === "integer") {

+                return Math.floor(value * 1);

+            } else {

+                return "" + value;

+            }

+        },

+        getValue: function() {

+            return this.value;

+        },

+        preBuild: function() {

+            var self = this;

+            this.input_type = 'select';

+            this.enum_options = [];

+            this.enum_values = [];

+            this.enum_display = [];

+

+            // Enum options enumerated

+            if (this.schema.enum) {

+                var display = this.schema.options && this.schema.options.enum_titles || [];

+

+                $each(this.schema.enum, function(i, option) {

+                    self.enum_options[i] = "" + option;

+                    self.enum_display[i] = "" + (display[i] || option);

+                    self.enum_values[i] = self.typecast(option);

+                });

+            }

+            // Boolean

+            else if (this.schema.type === "boolean") {

+                self.enum_display = this.schema.options && this.schema.options.enum_titles || ['true', 'false'];

+                self.enum_options = ['1', '0'];

+                self.enum_values = [true, false];

+            }

+            // Dynamic Enum

+            else if (this.schema.enumSource) {

+                this.enumSource = [];

+                this.enum_display = [];

+                this.enum_options = [];

+                this.enum_values = [];

+

+                // Shortcut declaration for using a single array

+                if (!(Array.isArray(this.schema.enumSource))) {

+                    if (this.schema.enumValue) {

+                        this.enumSource = [{

+                            source: this.schema.enumSource,

+                            value: this.schema.enumValue

+                        }];

+                    } else {

+                        this.enumSource = [{

+                            source: this.schema.enumSource

+                        }];

+                    }

+                } else {

+                    for (i = 0; i < this.schema.enumSource.length; i++) {

+                        // Shorthand for watched variable

+                        if (typeof this.schema.enumSource[i] === "string") {

+                            this.enumSource[i] = {

+                                source: this.schema.enumSource[i]

+                            };

+                        }

+                        // Make a copy of the schema

+                        else if (!(Array.isArray(this.schema.enumSource[i]))) {

+                            this.enumSource[i] = $extend({}, this.schema.enumSource[i]);

+                        } else {

+                            this.enumSource[i] = this.schema.enumSource[i];

+                        }

+                    }

+                }

+

+                // Now, enumSource is an array of sources

+                // Walk through this array and fix up the values

+                for (i = 0; i < this.enumSource.length; i++) {

+                    if (this.enumSource[i].value) {

+                        this.enumSource[i].value = this.jsoneditor.compileTemplate(this.enumSource[i].value, this.template_engine);

+                    }

+                    if (this.enumSource[i].title) {

+                        this.enumSource[i].title = this.jsoneditor.compileTemplate(this.enumSource[i].title, this.template_engine);

+                    }

+                    if (this.enumSource[i].filter) {

+                        this.enumSource[i].filter = this.jsoneditor.compileTemplate(this.enumSource[i].filter, this.template_engine);

+                    }

+                }

+            }

+            // Other, not supported

+            else {

+                throw "'select' editor requires the enum property to be set.";

+            }

+        },

+        build: function() {

+            var self = this;

+            if (!this.options.compact) this.header = this.label = this.theme.getFormInputLabel(this.getTitle());

+            if (this.schema.description) this.description = this.theme.getFormInputDescription(this.schema.description);

+

+            if (this.options.compact) this.container.className += ' compact';

+

+            this.input = this.theme.getSelectInput(this.enum_options);

+            this.theme.setSelectOptions(this.input, this.enum_options, this.enum_display);

+

+            if (this.schema.readOnly || this.schema.readonly) {

+                this.always_disabled = true;

+                this.input.disabled = true;

+            }

+

+            this.input.addEventListener('change', function(e) {

+                e.preventDefault();

+                e.stopPropagation();

+                self.onInputChange();

+            }, false);

+

+            this.control = this.theme.getFormControl(this.label, this.input, this.description);

+            this.container.appendChild(this.control);

+

+            this.value = this.enum_values[0];

+        },

+        onInputChange: function() {

+            var val = this.input.value;

+

+            var sanitized = val;

+            if (this.enum_options.indexOf(val) === -1) {

+                sanitized = this.enum_options[0];

+            }

+

+            this.value = this.enum_values[this.enum_options.indexOf(val)];

+            this.onChange(true);

+        },

+        setupSelectize: function() {

+            // If the Selectize library is loaded use it when we have lots of items

+            var self = this;

+            if (window.jQuery && window.jQuery.fn && window.jQuery.fn.selectize && (this.enum_options.length >= 2 || (this.enum_options.length && this.enumSource))) {

+                var options = $extend({}, JSONEditor.plugins.selectize);

+                if (this.schema.options && this.schema.options.selectize_options) options = $extend(options, this.schema.options.selectize_options);

+                this.selectize = window.jQuery(this.input).selectize($extend(options, {

+                    create: true,

+                    onChange: function() {

+                        self.onInputChange();

+                    }

+                }));

+            } else {

+                this.selectize = null;

+            }

+        },

+        postBuild: function() {

+            this._super();

+            this.theme.afterInputReady(this.input);

+            this.setupSelectize();

+        },

+        onWatchedFieldChange: function() {

+            var self = this,

+                vars, j;

+

+            // If this editor uses a dynamic select box

+            if (this.enumSource) {

+                vars = this.getWatchedFieldValues();

+                var select_options = [];

+                var select_titles = [];

+

+                for (var i = 0; i < this.enumSource.length; i++) {

+                    // Constant values

+                    if (Array.isArray(this.enumSource[i])) {

+                        select_options = select_options.concat(this.enumSource[i]);

+                        select_titles = select_titles.concat(this.enumSource[i]);

+                    }

+                    // A watched field

+                    else if (vars[this.enumSource[i].source]) {

+                        var items = vars[this.enumSource[i].source];

+

+                        // Only use a predefined part of the array

+                        if (this.enumSource[i].slice) {

+                            items = Array.prototype.slice.apply(items, this.enumSource[i].slice);

+                        }

+                        // Filter the items

+                        if (this.enumSource[i].filter) {

+                            var new_items = [];

+                            for (j = 0; j < items.length; j++) {

+                                if (this.enumSource[i].filter({

+                                    i: j,

+                                    item: items[j]

+                                })) new_items.push(items[j]);

+                            }

+                            items = new_items;

+                        }

+

+                        var item_titles = [];

+                        var item_values = [];

+                        for (j = 0; j < items.length; j++) {

+                            var item = items[j];

+

+                            // Rendered value

+                            if (this.enumSource[i].value) {

+                                item_values[j] = this.enumSource[i].value({

+                                    i: j,

+                                    item: item

+                                });

+                            }

+                            // Use value directly

+                            else {

+                                item_values[j] = items[j];

+                            }

+

+                            // Rendered title

+                            if (this.enumSource[i].title) {

+                                item_titles[j] = this.enumSource[i].title({

+                                    i: j,

+                                    item: item

+                                });

+                            }

+                            // Use value as the title also

+                            else {

+                                item_titles[j] = item_values[j];

+                            }

+                        }

+

+                        // TODO: sort

+

+                        select_options = select_options.concat(item_values);

+                        select_titles = select_titles.concat(item_titles);

+                    }

+                }

+

+                var prev_value = this.value;

+

+                this.theme.setSelectOptions(this.input, select_options, select_titles);

+                this.enum_options = select_options;

+                this.enum_display = select_titles;

+                this.enum_values = select_options;

+

+                // If the previous value is still in the new select options, stick with it

+                if (select_options.indexOf(prev_value) !== -1) {

+                    this.input.value = prev_value;

+                    this.value = prev_value;

+                }

+

+                // Otherwise, set the value to the first select option

+                else {

+                    this.input.value = select_options[0];

+                    this.value = select_options[0] || "";

+                    if (this.parent) this.parent.onChildEditorChange(this);

+                    else this.jsoneditor.onChange();

+                    this.jsoneditor.notifyWatchers(this.path);

+                }

+

+                if (this.selectize) {

+                    // Update the Selectize options

+                    this.updateSelectizeOptions(select_options);

+                } else {

+                    this.setupSelectize();

+                }

+

+                this._super();

+            }

+        },

+        updateSelectizeOptions: function(select_options) {

+            var selectized = this.selectize[0].selectize,

+                self = this;

+

+            selectized.off();

+            selectized.clearOptions();

+            for (var n in select_options) {

+                selectized.addOption({

+                    value: select_options[n],

+                    text: select_options[n]

+                });

+            }

+            selectized.addItem(this.value);

+            selectized.on('change', function() {

+                self.onInputChange();

+            });

+        },

+        enable: function() {

+            if (!this.always_disabled) {

+                this.input.disabled = false;

+                if (this.selectize) {

+                    this.selectize[0].selectize.unlock();

+                }

+            }

+            this._super();

+        },

+        disable: function() {

+            this.input.disabled = true;

+            if (this.selectize) {

+                this.selectize[0].selectize.lock();

+            }

+            this._super();

+        },

+        destroy: function() {

+            if (this.label && this.label.parentNode) this.label.parentNode.removeChild(this.label);

+            if (this.description && this.description.parentNode) this.description.parentNode.removeChild(this.description);

+            if (this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input);

+            if (this.selectize) {

+                this.selectize[0].selectize.destroy();

+                this.selectize = null;

+            }

+            this._super();

+        }

+    });

+

+    JSONEditor.defaults.editors.multiselect = JSONEditor.AbstractEditor.extend({

+        preBuild: function() {

+            this._super();

+

+            this.select_options = {};

+            this.select_values = {};

+

+            var items_schema = this.jsoneditor.expandRefs(this.schema.items || {});

+

+            var e = items_schema["enum"] || [];

+            this.option_keys = [];

+            for (i = 0; i < e.length; i++) {

+                // If the sanitized value is different from the enum value, don't include it

+                if (this.sanitize(e[i]) !== e[i]) continue;

+

+                this.option_keys.push(e[i] + "");

+                this.select_values[e[i] + ""] = e[i];

+            }

+        },

+        build: function() {

+            var self = this,

+                i;

+            if (!this.options.compact) this.header = this.label = this.theme.getFormInputLabel(this.getTitle());

+            if (this.schema.description) this.description = this.theme.getFormInputDescription(this.schema.description);

+

+            if ((!this.schema.format && this.option_keys.length < 8) || this.schema.format === "checkbox") {

+                this.input_type = 'checkboxes';

+

+                this.inputs = {};

+                this.controls = {};

+                for (i = 0; i < this.option_keys.length; i++) {

+                    this.inputs[this.option_keys[i]] = this.theme.getCheckbox();

+                    this.select_options[this.option_keys[i]] = this.inputs[this.option_keys[i]];

+                    var label = this.theme.getCheckboxLabel(this.option_keys[i]);

+                    this.controls[this.option_keys[i]] = this.theme.getFormControl(label, this.inputs[this.option_keys[i]]);

+                }

+

+                this.control = this.theme.getMultiCheckboxHolder(this.controls, this.label, this.description);

+            } else {

+                this.input_type = 'select';

+                this.input = this.theme.getSelectInput(this.option_keys);

+                this.input.multiple = true;

+                this.input.size = Math.min(10, this.option_keys.length);

+

+                for (i = 0; i < this.option_keys.length; i++) {

+                    this.select_options[this.option_keys[i]] = this.input.children[i];

+                }

+

+                if (this.schema.readOnly || this.schema.readonly) {

+                    this.always_disabled = true;

+                    this.input.disabled = true;

+                }

+

+                this.control = this.theme.getFormControl(this.label, this.input, this.description);

+            }

+

+            this.container.appendChild(this.control);

+            this.control.addEventListener('change', function(e) {

+                e.preventDefault();

+                e.stopPropagation();

+

+                var new_value = [];

+                for (i = 0; i < self.option_keys.length; i++) {

+                    if (self.select_options[self.option_keys[i]].selected || self.select_options[self.option_keys[i]].checked) new_value.push(self.select_values[self.option_keys[i]]);

+                }

+

+                self.updateValue(new_value);

+                self.onChange(true);

+            }, false);

+        },

+        setValue: function(value, initial) {

+            var i;

+            value = value || [];

+            if (typeof value !== "object") value = [value];

+            else if (!(Array.isArray(value))) value = [];

+

+            // Make sure we are dealing with an array of strings so we can check for strict equality

+            for (i = 0; i < value.length; i++) {

+                if (typeof value[i] !== "string") value[i] += "";

+            }

+

+            // Update selected status of options

+            for (i in this.select_options) {

+                if (!this.select_options.hasOwnProperty(i)) continue;

+

+                this.select_options[i][this.input_type === "select" ? "selected" : "checked"] = (value.indexOf(i) !== -1);

+            }

+

+            this.updateValue(value);

+            this.onChange();

+        },

+        setupSelect2: function() {

+            if (window.jQuery && window.jQuery.fn && window.jQuery.fn.select2) {

+                var options = window.jQuery.extend({}, JSONEditor.plugins.select2);

+                if (this.schema.options && this.schema.options.select2_options) options = $extend(options, this.schema.options.select2_options);

+                this.select2 = window.jQuery(this.input).select2(options);

+                var self = this;

+                this.select2.on('select2-blur', function() {

+                    var val = self.select2.select2('val');

+                    self.value = val;

+                    self.onChange(true);

+                });

+            } else {

+                this.select2 = null;

+            }

+        },

+        onInputChange: function() {

+            this.value = this.input.value;

+            this.onChange(true);

+        },

+        postBuild: function() {

+            this._super();

+            this.setupSelect2();

+        },

+        register: function() {

+            this._super();

+            if (!this.input) return;

+            this.input.setAttribute('name', this.formname);

+        },

+        unregister: function() {

+            this._super();

+            if (!this.input) return;

+            this.input.removeAttribute('name');

+        },

+        getNumColumns: function() {

+            var longest_text = this.getTitle().length;

+            for (var i in this.select_values) {

+                if (!this.select_values.hasOwnProperty(i)) continue;

+                longest_text = Math.max(longest_text, (this.select_values[i] + "").length + 4);

+            }

+

+            return Math.min(12, Math.max(longest_text / 7, 2));

+        },

+        updateValue: function(value) {

+            var changed = false;

+            var new_value = [];

+            for (var i = 0; i < value.length; i++) {

+                if (!this.select_options[value[i] + ""]) {

+                    changed = true;

+                    continue;

+                }

+                var sanitized = this.sanitize(this.select_values[value[i]]);

+                new_value.push(sanitized);

+                if (sanitized !== value[i]) changed = true;

+            }

+            this.value = new_value;

+            if (this.select2) this.select2.select2('val', this.value);

+            return changed;

+        },

+        sanitize: function(value) {

+            if (this.schema.items.type === "number") {

+                return 1 * value;

+            } else if (this.schema.items.type === "integer") {

+                return Math.floor(value * 1);

+            } else {

+                return "" + value;

+            }

+        },

+        enable: function() {

+            if (!this.always_disabled) {

+                if (this.input) {

+                    this.input.disabled = false;

+                } else if (this.inputs) {

+                    for (var i in this.inputs) {

+                        if (!this.inputs.hasOwnProperty(i)) continue;

+                        this.inputs[i].disabled = false;

+                    }

+                }

+                if (this.select2) this.select2.select2("enable", true);

+            }

+            this._super();

+        },

+        disable: function() {

+            if (this.input) {

+                this.input.disabled = true;

+            } else if (this.inputs) {

+                for (var i in this.inputs) {

+                    if (!this.inputs.hasOwnProperty(i)) continue;

+                    this.inputs[i].disabled = true;

+                }

+            }

+            if (this.select2) this.select2.select2("enable", false);

+            this._super();

+        },

+        destroy: function() {

+            if (this.select2) {

+                this.select2.select2('destroy');

+                this.select2 = null;

+            }

+            this._super();

+        }

+    });

+

+    JSONEditor.defaults.editors.base64 = JSONEditor.AbstractEditor.extend({

+        getNumColumns: function() {

+            return 4;

+        },

+        build: function() {

+            var self = this;

+            this.title = this.header = this.label = this.theme.getFormInputLabel(this.getTitle());

+

+            // Input that holds the base64 string

+            this.input = this.theme.getFormInputField('hidden');

+            this.container.appendChild(this.input);

+

+            // Don't show uploader if this is readonly

+            if (!this.schema.readOnly && !this.schema.readonly) {

+                if (!window.FileReader) throw "FileReader required for base64 editor";

+

+                // File uploader

+                this.uploader = this.theme.getFormInputField('file');

+

+                this.uploader.addEventListener('change', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+

+                    if (this.files && this.files.length) {

+                        var fr = new FileReader();

+                        fr.onload = function(evt) {

+                            self.value = evt.target.result;

+                            self.refreshPreview();

+                            self.onChange(true);

+                            fr = null;

+                        };

+                        fr.readAsDataURL(this.files[0]);

+                    }

+                }, false);

+            }

+

+            this.preview = this.theme.getFormInputDescription(this.schema.description);

+            this.container.appendChild(this.preview);

+

+            this.control = this.theme.getFormControl(this.label, this.uploader || this.input, this.preview);

+            this.container.appendChild(this.control);

+        },

+        refreshPreview: function() {

+            if (this.last_preview === this.value) return;

+            this.last_preview = this.value;

+

+            this.preview.innerHTML = '';

+

+            if (!this.value) return;

+

+            var mime = this.value.match(/^data:([^;,]+)[;,]/);

+            if (mime) mime = mime[1];

+

+            if (!mime) {

+                this.preview.innerHTML = '<em>Invalid data URI</em>';

+            } else {

+                this.preview.innerHTML = '<strong>Type:</strong> ' + mime + ', <strong>Size:</strong> ' + Math.floor((this.value.length - this.value.split(',')[0].length - 1) / 1.33333) + ' bytes';

+                if (mime.substr(0, 5) === "image") {

+                    this.preview.innerHTML += '<br>';

+                    var img = document.createElement('img');

+                    img.style.maxWidth = '100%';

+                    img.style.maxHeight = '100px';

+                    img.src = this.value;

+                    this.preview.appendChild(img);

+                }

+            }

+        },

+        enable: function() {

+            if (this.uploader) this.uploader.disabled = false;

+            this._super();

+        },

+        disable: function() {

+            if (this.uploader) this.uploader.disabled = true;

+            this._super();

+        },

+        setValue: function(val) {

+            if (this.value !== val) {

+                this.value = val;

+                this.input.value = this.value;

+                this.refreshPreview();

+                this.onChange();

+            }

+        },

+        destroy: function() {

+            if (this.preview && this.preview.parentNode) this.preview.parentNode.removeChild(this.preview);

+            if (this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title);

+            if (this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input);

+            if (this.uploader && this.uploader.parentNode) this.uploader.parentNode.removeChild(this.uploader);

+

+            this._super();

+        }

+    });

+

+    JSONEditor.defaults.editors.upload = JSONEditor.AbstractEditor.extend({

+        getNumColumns: function() {

+            return 4;

+        },

+        build: function() {

+            var self = this;

+            this.title = this.header = this.label = this.theme.getFormInputLabel(this.getTitle());

+

+            // Input that holds the base64 string

+            this.input = this.theme.getFormInputField('hidden');

+            this.container.appendChild(this.input);

+

+            // Don't show uploader if this is readonly

+            if (!this.schema.readOnly && !this.schema.readonly) {

+

+                if (!this.jsoneditor.options.upload) throw "Upload handler required for upload editor";

+

+                // File uploader

+                this.uploader = this.theme.getFormInputField('file');

+

+                this.uploader.addEventListener('change', function(e) {

+                    e.preventDefault();

+                    e.stopPropagation();

+

+                    if (this.files && this.files.length) {

+                        var fr = new FileReader();

+                        fr.onload = function(evt) {

+                            self.preview_value = evt.target.result;

+                            self.refreshPreview();

+                            self.onChange(true);

+                            fr = null;

+                        };

+                        fr.readAsDataURL(this.files[0]);

+                    }

+                }, false);

+            }

+

+            var description = this.schema.description;

+            if (!description) description = '';

+

+            this.preview = this.theme.getFormInputDescription(description);

+            this.container.appendChild(this.preview);

+

+            this.control = this.theme.getFormControl(this.label, this.uploader || this.input, this.preview);

+            this.container.appendChild(this.control);

+        },

+        refreshPreview: function() {

+            if (this.last_preview === this.preview_value) return;

+            this.last_preview = this.preview_value;

+

+            this.preview.innerHTML = '';

+

+            if (!this.preview_value) return;

+

+            var self = this;

+

+            var mime = this.preview_value.match(/^data:([^;,]+)[;,]/);

+            if (mime) mime = mime[1];

+            if (!mime) mime = 'unknown';

+

+            var file = this.uploader.files[0];

+

+            this.preview.innerHTML = '<strong>Type:</strong> ' + mime + ', <strong>Size:</strong> ' + file.size + ' bytes';

+            if (mime.substr(0, 5) === "image") {

+                this.preview.innerHTML += '<br>';

+                var img = document.createElement('img');

+                img.style.maxWidth = '100%';

+                img.style.maxHeight = '100px';

+                img.src = this.preview_value;

+                this.preview.appendChild(img);

+            }

+

+            this.preview.innerHTML += '<br>';

+            var uploadButton = this.getButton('Upload', 'upload', 'Upload');

+            this.preview.appendChild(uploadButton);

+            uploadButton.addEventListener('click', function(event) {

+                event.preventDefault();

+

+                uploadButton.setAttribute("disabled", "disabled");

+                self.theme.removeInputError(self.uploader);

+

+                if (self.theme.getProgressBar) {

+                    self.progressBar = self.theme.getProgressBar();

+                    self.preview.appendChild(self.progressBar);

+                }

+

+                self.jsoneditor.options.upload(self.path, file, {

+                    success: function(url) {

+                        self.setValue(url);

+

+                        if (self.parent) self.parent.onChildEditorChange(self);

+                        else self.jsoneditor.onChange();

+

+                        if (self.progressBar) self.preview.removeChild(self.progressBar);

+                        uploadButton.removeAttribute("disabled");

+                    },

+                    failure: function(error) {

+                        self.theme.addInputError(self.uploader, error);

+                        if (self.progressBar) self.preview.removeChild(self.progressBar);

+                        uploadButton.removeAttribute("disabled");

+                    },

+                    updateProgress: function(progress) {

+                        if (self.progressBar) {

+                            if (progress) self.theme.updateProgressBar(self.progressBar, progress);

+                            else self.theme.updateProgressBarUnknown(self.progressBar);

+                        }

+                    }

+                });

+            }, false);

+        },

+        enable: function() {

+            if (this.uploader) this.uploader.disabled = false;

+            this._super();

+        },

+        disable: function() {

+            if (this.uploader) this.uploader.disabled = true;

+            this._super();

+        },

+        setValue: function(val) {

+            if (this.value !== val) {

+                this.value = val;

+                this.input.value = this.value;

+                this.onChange();

+            }

+        },

+        destroy: function() {

+            if (this.preview && this.preview.parentNode) this.preview.parentNode.removeChild(this.preview);

+            if (this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title);

+            if (this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input);

+            if (this.uploader && this.uploader.parentNode) this.uploader.parentNode.removeChild(this.uploader);

+

+            this._super();

+        }

+    });

+

+    JSONEditor.defaults.editors.checkbox = JSONEditor.AbstractEditor.extend({

+        setValue: function(value, initial) {

+            this.value = !! value;

+            this.input.checked = this.value;

+            this.onChange();

+        },

+        register: function() {

+            this._super();

+            if (!this.input) return;

+            this.input.setAttribute('name', this.formname);

+        },

+        unregister: function() {

+            this._super();

+            if (!this.input) return;

+            this.input.removeAttribute('name');

+        },

+        getNumColumns: function() {

+            return Math.min(12, Math.max(this.getTitle().length / 7, 2));

+        },

+        build: function() {

+            var self = this;

+            if (!this.options.compact) {

+                this.label = this.header = this.theme.getCheckboxLabel(this.getTitle());

+            }

+            if (this.schema.description) this.description = this.theme.getFormInputDescription(this.schema.description);

+            if (this.options.compact) this.container.className += ' compact';

+

+            this.input = this.theme.getCheckbox();

+            this.control = this.theme.getFormControl(this.label, this.input, this.description);

+

+            if (this.schema.readOnly || this.schema.readonly) {

+                this.always_disabled = true;

+                this.input.disabled = true;

+            }

+

+            this.input.addEventListener('change', function(e) {

+                e.preventDefault();

+                e.stopPropagation();

+                self.value = this.checked;

+                self.onChange(true);

+            }, false);

+

+            this.container.appendChild(this.control);

+        },

+        enable: function() {

+            if (!this.always_disabled) {

+                this.input.disabled = false;

+            }

+            this._super();

+        },

+        disable: function() {

+            this.input.disabled = true;

+            this._super();

+        },

+        destroy: function() {

+            if (this.label && this.label.parentNode) this.label.parentNode.removeChild(this.label);

+            if (this.description && this.description.parentNode) this.description.parentNode.removeChild(this.description);

+            if (this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input);

+            this._super();

+        }

+    });

+

+    JSONEditor.defaults.editors.arraySelectize = JSONEditor.AbstractEditor.extend({

+        build: function() {

+            this.title = this.theme.getFormInputLabel(this.getTitle());

+

+            this.title_controls = this.theme.getHeaderButtonHolder();

+            this.title.appendChild(this.title_controls);

+            this.error_holder = document.createElement('div');

+

+            if (this.schema.description) {

+                this.description = this.theme.getDescription(this.schema.description);

+            }

+

+            this.input = document.createElement('select');

+            this.input.setAttribute('multiple', 'multiple');

+

+            var group = this.theme.getFormControl(this.title, this.input, this.description);

+

+            this.container.appendChild(group);

+            this.container.appendChild(this.error_holder);

+

+            window.jQuery(this.input).selectize({

+                delimiter: false,

+                createOnBlur: true,

+                create: true

+            });

+        },

+        postBuild: function() {

+            var self = this;

+            this.input.selectize.on('change', function(event) {

+                self.refreshValue();

+                self.onChange(true);

+            });

+        },

+        destroy: function() {

+            this.empty(true);

+            if (this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title);

+            if (this.description && this.description.parentNode) this.description.parentNode.removeChild(this.description);

+            if (this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input);

+

+            this._super();

+        },

+        empty: function(hard) {},

+        setValue: function(value, initial) {

+            var self = this;

+            // Update the array's value, adding/removing rows when necessary

+            value = value || [];

+            if (!(Array.isArray(value))) value = [value];

+

+            this.input.selectize.clearOptions();

+            this.input.selectize.clear(true);

+

+            value.forEach(function(item) {

+                self.input.selectize.addOption({

+                    text: item,

+                    value: item

+                });

+            });

+            this.input.selectize.setValue(value);

+

+            this.refreshValue(initial);

+        },

+        refreshValue: function(force) {

+            this.value = this.input.selectize.getValue();

+        },

+        showValidationErrors: function(errors) {

+            var self = this;

+

+            // Get all the errors that pertain to this editor

+            var my_errors = [];

+            var other_errors = [];

+            $each(errors, function(i, error) {

+                if (error.path === self.path) {

+                    my_errors.push(error);

+                } else {

+                    other_errors.push(error);

+                }

+            });

+

+            // Show errors for this editor

+            if (this.error_holder) {

+

+                if (my_errors.length) {

+                    var message = [];

+                    this.error_holder.innerHTML = '';

+                    this.error_holder.style.display = '';

+                    $each(my_errors, function(i, error) {

+                        self.error_holder.appendChild(self.theme.getErrorMessage(error.message));

+                    });

+                }

+                // Hide error area

+                else {

+                    this.error_holder.style.display = 'none';

+                }

+            }

+        }

+    });

+

+    var matchKey = (function() {

+        var elem = document.documentElement;

+

+        if (elem.matches) return 'matches';

+        else if (elem.webkitMatchesSelector) return 'webkitMatchesSelector';

+        else if (elem.mozMatchesSelector) return 'mozMatchesSelector';

+        else if (elem.msMatchesSelector) return 'msMatchesSelector';

+        else if (elem.oMatchesSelector) return 'oMatchesSelector';

+    })();

+

+    JSONEditor.AbstractTheme = Class.extend({

+        getContainer: function() {

+            return document.createElement('div');

+        },

+        getFloatRightLinkHolder: function() {

+            var el = document.createElement('div');

+            el.setAttribute('style', el.style || {} );

+            el.style.cssFloat = 'right';

+            el.style.marginLeft = '10px';

+            return el;

+        },

+        getModal: function() {

+            var el = document.createElement('div');

+            el.style.backgroundColor = 'white';

+            el.style.border = '1px solid black';

+            el.style.boxShadow = '3px 3px black';

+            el.style.position = 'absolute';

+            el.style.zIndex = '10';

+            el.style.display = 'none';

+            return el;

+        },

+        getGridContainer: function() {

+            var el = document.createElement('div');

+            return el;

+        },

+        getGridRow: function() {

+            var el = document.createElement('div');

+            el.className = 'row';

+            return el;

+        },

+        getGridColumn: function() {

+            var el = document.createElement('div');

+            return el;

+        },

+        setGridColumnSize: function(el, size) {

+

+        },

+        getLink: function(text) {

+            var el = document.createElement('a');

+            el.setAttribute('href', '#');

+            el.appendChild(document.createTextNode(text));

+            return el;

+        },

+        disableHeader: function(header) {

+            header.style.color = '#ccc';

+        },

+        disableLabel: function(label) {

+            label.style.color = '#ccc';

+        },

+        enableHeader: function(header) {

+            header.style.color = '';

+        },

+        enableLabel: function(label) {

+            label.style.color = '';

+        },

+        getFormInputLabel: function(text) {

+            var el = document.createElement('label');

+            el.appendChild(document.createTextNode(text));

+            return el;

+        },

+        getCheckboxLabel: function(text) {

+            var el = this.getFormInputLabel(text);

+            el.style.fontWeight = 'normal';

+            return el;

+        },

+        getHeader: function(text) {

+            var el = document.createElement('h3');

+            if (typeof text === "string") {

+                el.textContent = text;

+            } else {

+                el.appendChild(text);

+            }

+

+            return el;

+        },

+        getCheckbox: function() {

+            var el = this.getFormInputField('checkbox');

+            el.style.display = 'inline-block';

+            el.style.width = 'auto';

+            return el;

+        },

+        getMultiCheckboxHolder: function(controls, label, description) {

+            var el = document.createElement('div');

+

+            if (label) {

+                label.style.display = 'block';

+                el.appendChild(label);

+            }

+

+            for (var i in controls) {

+                if (!controls.hasOwnProperty(i)) continue;

+                controls[i].style.display = 'inline-block';

+                controls[i].style.marginRight = '20px';

+                el.appendChild(controls[i]);

+            }

+

+            if (description) el.appendChild(description);

+

+            return el;

+        },

+        getSelectInput: function(options) {

+            var select = document.createElement('select');

+            if (options) this.setSelectOptions(select, options);

+            return select;

+        },

+        getSwitcher: function(options) {

+            var switcher = this.getSelectInput(options);

+            switcher.style.backgroundColor = 'transparent';

+            switcher.style.display = 'inline-block';

+            switcher.style.fontStyle = 'italic';

+            switcher.style.fontWeight = 'normal';

+            switcher.style.height = 'auto';

+            switcher.style.marginBottom = 0;

+            switcher.style.marginLeft = '5px';

+            switcher.style.padding = '0 0 0 3px';

+            switcher.style.width = 'auto';

+            return switcher;

+        },

+        getSwitcherOptions: function(switcher) {

+            return switcher.getElementsByTagName('option');

+        },

+        setSwitcherOptions: function(switcher, options, titles) {

+            this.setSelectOptions(switcher, options, titles);

+        },

+        setSelectOptions: function(select, options, titles) {

+            titles = titles || [];

+            select.innerHTML = '';

+            for (var i = 0; i < options.length; i++) {

+                var option = document.createElement('option');

+                option.setAttribute('value', options[i]);

+                option.textContent = titles[i] || options[i];

+                select.appendChild(option);

+            }

+        },

+        getTextareaInput: function() {

+            var el = document.createElement('textarea');

+            el.setAttribute('style', el.style || {} );

+            el.style.width = '100%';

+            el.style.height = '300px';

+            el.style.boxSizing = 'border-box';

+            return el;

+        },

+        getRangeInput: function(min, max, step) {

+            var el = this.getFormInputField('range');

+            el.setAttribute('min', min);

+            el.setAttribute('max', max);

+            el.setAttribute('step', step);

+            return el;

+        },

+        getFormInputField: function(type) {

+            var el = document.createElement('input');

+            el.setAttribute('type', type);

+            return el;

+        },

+        afterInputReady: function(input) {

+

+        },

+        getFormControl: function(label, input, description) {

+            var el = document.createElement('div');

+            el.className = 'form-control';

+            if (label) el.appendChild(label);

+            if (input.type === 'checkbox') {

+                label.insertBefore(input, label.firstChild);

+            } else {

+                el.appendChild(input);

+            }

+

+            if (description) el.appendChild(description);

+            return el;

+        },

+        getIndentedPanel: function() {

+            var el = document.createElement('div');

+            el.setAttribute('style', el.style || {} );

+            el.style.paddingLeft = '10px';

+            el.style.marginLeft = '10px';

+            el.style.borderLeft = '1px solid #ccc';

+            return el;

+        },

+        getChildEditorHolder: function() {

+            return document.createElement('div');

+        },

+        getDescription: function(text) {

+            var el = document.createElement('p');

+            el.innerHTML = text;

+            return el;

+        },

+        getCheckboxDescription: function(text) {

+            return this.getDescription(text);

+        },

+        getFormInputDescription: function(text) {

+            return this.getDescription(text);

+        },

+        getHeaderButtonHolder: function() {

+            return this.getButtonHolder();

+        },

+        getButtonHolder: function() {

+            return document.createElement('div');

+        },

+        getButton: function(text, icon, title) {

+            var el = document.createElement('button');

+            el.type = 'button';

+            this.setButtonText(el, text, icon, title);

+            return el;

+        },

+        setButtonText: function(button, text, icon, title) {

+            button.innerHTML = '';

+            if (icon) {

+                button.appendChild(icon);

+                button.innerHTML += ' ';

+            }

+            button.appendChild(document.createTextNode(text));

+            if (title) button.setAttribute('title', title);

+        },

+        getTable: function() {

+            return document.createElement('table');

+        },

+        getTableRow: function() {

+            return document.createElement('tr');

+        },

+        getTableHead: function() {

+            return document.createElement('thead');

+        },

+        getTableBody: function() {

+            return document.createElement('tbody');

+        },

+        getTableHeaderCell: function(text) {

+            var el = document.createElement('th');

+            el.textContent = text;

+            return el;

+        },

+        getTableCell: function() {

+            var el = document.createElement('td');

+            return el;

+        },

+        getErrorMessage: function(text) {

+            var el = document.createElement('p');

+            el.setAttribute('style', el.style || {} );

+            el.style.color = 'red';

+            el.appendChild(document.createTextNode(text));

+            return el;

+        },

+        addInputError: function(input, text) {},

+        removeInputError: function(input) {},

+        addTableRowError: function(row) {},

+        removeTableRowError: function(row) {},

+        getTabHolder: function() {

+            var el = document.createElement('div');

+            el.innerHTML = "<div style='float: left; width: 130px;' class='tabs'></div><div class='content' style='margin-left: 130px;'></div><div style='clear:both;'></div>";

+            return el;

+        },

+        applyStyles: function(el, styles) {

+            el.setAttribute('style', el.style || {} );

+            for (var i in styles) {

+                if (!styles.hasOwnProperty(i)) continue;

+                el.style[i] = styles[i];

+            }

+        },

+        closest: function(elem, selector) {

+            while (elem && elem !== document) {

+                if (matchKey) {

+                    if (elem[matchKey](selector)) {

+                        return elem;

+                    } else {

+                        elem = elem.parentNode;

+                    }

+                } else {

+                    return false;

+                }

+            }

+            return false;

+        },

+        getTab: function(span) {

+            var el = document.createElement('div');

+            el.appendChild(span);

+            el.setAttribute('style', el.style || {} );

+            this.applyStyles(el, {

+                border: '1px solid #ccc',

+                borderWidth: '1px 0 1px 1px',

+                textAlign: 'center',

+                lineHeight: '30px',

+                borderRadius: '5px',

+                borderBottomRightRadius: 0,

+                borderTopRightRadius: 0,

+                fontWeight: 'bold',

+                cursor: 'pointer'

+            });

+            return el;

+        },

+        getTabContentHolder: function(tab_holder) {

+            return tab_holder.children[1];

+        },

+        getTabContent: function() {

+            return this.getIndentedPanel();

+        },

+        markTabActive: function(tab) {

+            this.applyStyles(tab, {

+                opacity: 1,

+                background: 'white'

+            });

+        },

+        markTabInactive: function(tab) {

+            this.applyStyles(tab, {

+                opacity: 0.5,

+                background: ''

+            });

+        },

+        addTab: function(holder, tab) {

+            holder.children[0].appendChild(tab);

+        },

+        getBlockLink: function() {

+            var link = document.createElement('a');

+            link.style.display = 'block';

+            return link;

+        },

+        getBlockLinkHolder: function() {

+            var el = document.createElement('div');

+            return el;

+        },

+        getLinksHolder: function() {

+            var el = document.createElement('div');

+            return el;

+        },

+        createMediaLink: function(holder, link, media) {

+            holder.appendChild(link);

+            media.style.width = '100%';

+            holder.appendChild(media);

+        },

+        createImageLink: function(holder, link, image) {

+            holder.appendChild(link);

+            link.appendChild(image);

+        }

+    });

+

+    JSONEditor.defaults.themes.bootstrap2 = JSONEditor.AbstractTheme.extend({

+        getRangeInput: function(min, max, step) {

+            // TODO: use bootstrap slider

+            return this._super(min, max, step);

+        },

+        getGridContainer: function() {

+            var el = document.createElement('div');

+            el.className = 'container-fluid';

+            return el;

+        },

+        getGridRow: function() {

+            var el = document.createElement('div');

+            el.className = 'row-fluid';

+            return el;

+        },

+        getFormInputLabel: function(text) {

+            var el = this._super(text);

+            el.style.display = 'inline-block';

+            el.style.fontWeight = 'bold';

+            return el;

+        },

+        setGridColumnSize: function(el, size) {

+            el.className = 'span' + size;

+        },

+        getSelectInput: function(options) {

+            var input = this._super(options);

+            input.style.width = 'auto';

+            input.style.maxWidth = '98%';

+            return input;

+        },

+        getFormInputField: function(type) {

+            var el = this._super(type);

+            el.style.width = '98%';

+            return el;

+        },

+        afterInputReady: function(input) {

+            if (input.controlgroup) return;

+            input.controlgroup = this.closest(input, '.control-group');

+            input.controls = this.closest(input, '.controls');

+            if (this.closest(input, '.compact')) {

+                input.controlgroup.className = input.controlgroup.className.replace(/control-group/g, '').replace(/[ ]{2,}/g, ' ');

+                input.controls.className = input.controlgroup.className.replace(/controls/g, '').replace(/[ ]{2,}/g, ' ');

+                input.style.marginBottom = 0;

+            }

+

+            // TODO: use bootstrap slider

+        },

+        getIndentedPanel: function() {

+            var el = document.createElement('div');

+            el.className = 'well well-small';

+            el.style.paddingBottom = 0;

+            return el;

+        },

+        getFormInputDescription: function(text) {

+            var el = document.createElement('p');

+            el.className = 'help-inline';

+            el.textContent = text;

+            return el;

+        },

+        getFormControl: function(label, input, description) {

+            var ret = document.createElement('div');

+            ret.className = 'control-group';

+

+            var controls = document.createElement('div');

+            controls.className = 'controls';

+

+            if (label && input.getAttribute('type') === 'checkbox') {

+                ret.appendChild(controls);

+                label.className += ' checkbox';

+                label.appendChild(input);

+                controls.appendChild(label);

+                controls.style.height = '30px';

+            } else {

+                if (label) {

+                    label.className += ' control-label';

+                    ret.appendChild(label);

+                }

+                controls.appendChild(input);

+                ret.appendChild(controls);

+            }

+

+            if (description) controls.appendChild(description);

+

+            return ret;

+        },

+        getHeaderButtonHolder: function() {

+            var el = this.getButtonHolder();

+            el.style.marginLeft = '10px';

+            return el;

+        },

+        getButtonHolder: function() {

+            var el = document.createElement('div');

+            el.className = 'btn-group';

+            return el;

+        },

+        getButton: function(text, icon, title) {

+            var el = this._super(text, icon, title);

+            el.className += ' btn btn-default';

+            return el;

+        },

+        getTable: function() {

+            var el = document.createElement('table');

+            el.className = 'table table-bordered';

+            el.style.width = 'auto';

+            el.style.maxWidth = 'none';

+            return el;

+        },

+        addInputError: function(input, text) {

+            if (!input.controlgroup || !input.controls) return;

+            input.controlgroup.className += ' error';

+            if (!input.errmsg) {

+                input.errmsg = document.createElement('p');

+                input.errmsg.className = 'help-block errormsg';

+                input.controls.appendChild(input.errmsg);

+            } else {

+                input.errmsg.style.display = '';

+            }

+

+            input.errmsg.textContent = text;

+        },

+        removeInputError: function(input) {

+            if (!input.errmsg) return;

+            input.errmsg.style.display = 'none';

+            input.controlgroup.className = input.controlgroup.className.replace(/\s?error/g, '');

+        },

+        getTabHolder: function() {

+            var el = document.createElement('div');

+            el.className = 'tabbable tabs-left';

+            el.innerHTML = "<ul class='nav nav-tabs span2' style='margin-right: 0;'></ul><div class='tab-content span10' style='overflow:visible;'></div>";

+            return el;

+        },

+        getTab: function(text) {

+            var el = document.createElement('li');

+            var a = document.createElement('a');

+            a.setAttribute('href', '#');

+            a.appendChild(text);

+            el.appendChild(a);

+            return el;

+        },

+        getTabContentHolder: function(tab_holder) {

+            return tab_holder.children[1];

+        },

+        getTabContent: function() {

+            var el = document.createElement('div');

+            el.className = 'tab-pane active';

+            return el;

+        },

+        markTabActive: function(tab) {

+            tab.className += ' active';

+        },

+        markTabInactive: function(tab) {

+            tab.className = tab.className.replace(/\s?active/g, '');

+        },

+        addTab: function(holder, tab) {

+            holder.children[0].appendChild(tab);

+        },

+        getProgressBar: function() {

+            var container = document.createElement('div');

+            container.className = 'progress';

+

+            var bar = document.createElement('div');

+            bar.className = 'bar';

+            bar.style.width = '0%';

+            container.appendChild(bar);

+

+            return container;

+        },

+        updateProgressBar: function(progressBar, progress) {

+            if (!progressBar) return;

+

+            progressBar.firstChild.style.width = progress + "%";

+        },

+        updateProgressBarUnknown: function(progressBar) {

+            if (!progressBar) return;

+

+            progressBar.className = 'progress progress-striped active';

+            progressBar.firstChild.style.width = '100%';

+        }

+    });

+

+    JSONEditor.defaults.themes.bootstrap3 = JSONEditor.AbstractTheme.extend({

+        getSelectInput: function(options) {

+            var el = this._super(options);

+            el.className += 'form-control';

+            //el.style.width = 'auto';

+            return el;

+        },

+        setGridColumnSize: function(el, size) {

+            el.className = 'col-md-' + size;

+        },

+        afterInputReady: function(input) {

+            if (input.controlgroup) return;

+            input.controlgroup = this.closest(input, '.form-group');

+            if (this.closest(input, '.compact')) {

+                input.controlgroup.style.marginBottom = 0;

+            }

+

+            // TODO: use bootstrap slider

+        },

+        getTextareaInput: function() {

+            var el = document.createElement('textarea');

+            el.className = 'form-control';

+            return el;

+        },

+        getRangeInput: function(min, max, step) {

+            // TODO: use better slider

+            return this._super(min, max, step);

+        },

+        getFormInputField: function(type) {

+            var el = this._super(type);

+            if (type !== 'checkbox') {

+                el.className += 'form-control';

+            }

+            return el;

+        },

+        getFormControl: function(label, input, description) {

+            var group = document.createElement('div');

+

+            if (label && input.type === 'checkbox') {

+                group.className += ' checkbox';

+                label.appendChild(input);

+                label.style.fontSize = '14px';

+                group.style.marginTop = '0';

+                group.appendChild(label);

+                input.style.position = 'relative';

+                input.style.cssFloat = 'left';

+            } else {

+                group.className += ' form-group';

+                if (label) {

+                    label.className += ' control-label';

+                    group.appendChild(label);

+                }

+                group.appendChild(input);

+            }

+

+            if (description) group.appendChild(description);

+

+            return group;

+        },

+        getIndentedPanel: function() {

+            var el = document.createElement('div');

+            el.className = 'well well-sm';

+            el.style.paddingBottom = 0;

+            return el;

+        },

+        getFormInputDescription: function(text) {

+            var el = document.createElement('p');

+            el.className = 'help-block';

+            el.innerHTML = text;

+            return el;

+        },

+        getHeaderButtonHolder: function() {

+            var el = this.getButtonHolder();

+            el.style.marginLeft = '10px';

+            return el;

+        },

+        getButtonHolder: function() {

+            var el = document.createElement('div');

+            el.className = 'btn-group';

+            return el;

+        },

+        getButton: function(text, icon, title) {

+            var el = this._super(text, icon, title);

+            el.className += 'btn btn-default';

+            return el;

+        },

+        getTable: function() {

+            var el = document.createElement('table');

+            el.className = 'table table-bordered';

+            el.style.width = 'auto';

+            el.style.maxWidth = 'none';

+            return el;

+        },

+

+        addInputError: function(input, text) {

+            if (!input.controlgroup) return;

+            input.controlgroup.className += ' has-error';

+            if (!input.errmsg) {

+                input.errmsg = document.createElement('p');

+                input.errmsg.className = 'help-block errormsg';

+                input.controlgroup.appendChild(input.errmsg);

+            } else {

+                input.errmsg.style.display = '';

+            }

+

+            input.errmsg.textContent = text;

+        },

+        removeInputError: function(input) {

+            if (!input.errmsg) return;

+            input.errmsg.style.display = 'none';

+            input.controlgroup.className = input.controlgroup.className.replace(/\s?has-error/g, '');

+        },

+        getTabHolder: function() {

+            var el = document.createElement('div');

+            el.innerHTML = "<div class='tabs list-group col-md-2'></div><div class='col-md-10'></div>";

+            el.className = 'rows';

+            return el;

+        },

+        getTab: function(text) {

+            var el = document.createElement('a');

+            el.className = 'list-group-item';

+            el.setAttribute('href', '#');

+            el.appendChild(text);

+            return el;

+        },

+        markTabActive: function(tab) {

+            tab.className += ' active';

+        },

+        markTabInactive: function(tab) {

+            tab.className = tab.className.replace(/\s?active/g, '');

+        },

+        getProgressBar: function() {

+            var min = 0,

+                max = 100,

+                start = 0;

+

+            var container = document.createElement('div');

+            container.className = 'progress';

+

+            var bar = document.createElement('div');

+            bar.className = 'progress-bar';

+            bar.setAttribute('role', 'progressbar');

+            bar.setAttribute('aria-valuenow', start);

+            bar.setAttribute('aria-valuemin', min);

+            bar.setAttribute('aria-valuenax', max);

+            bar.innerHTML = start + "%";

+            container.appendChild(bar);

+

+            return container;

+        },

+        updateProgressBar: function(progressBar, progress) {

+            if (!progressBar) return;

+

+            var bar = progressBar.firstChild;

+            var percentage = progress + "%";

+            bar.setAttribute('aria-valuenow', progress);

+            bar.style.width = percentage;

+            bar.innerHTML = percentage;

+        },

+        updateProgressBarUnknown: function(progressBar) {

+            if (!progressBar) return;

+

+            var bar = progressBar.firstChild;

+            progressBar.className = 'progress progress-striped active';

+            bar.removeAttribute('aria-valuenow');

+            bar.style.width = '100%';

+            bar.innerHTML = '';

+        }

+    });

+

+    // Base Foundation theme

+    JSONEditor.defaults.themes.foundation = JSONEditor.AbstractTheme.extend({

+        getChildEditorHolder: function() {

+            var el = document.createElement('div');

+            el.style.marginBottom = '15px';

+            return el;

+        },

+        getSelectInput: function(options) {

+            var el = this._super(options);

+            el.style.minWidth = 'none';

+            el.style.padding = '5px';

+            el.style.marginTop = '3px';

+            return el;

+        },

+        getSwitcher: function(options) {

+            var el = this._super(options);

+            el.style.paddingRight = '8px';

+            return el;

+        },

+        afterInputReady: function(input) {

+            if (this.closest(input, '.compact')) {

+                input.style.marginBottom = 0;

+            }

+            input.group = this.closest(input, '.form-control');

+        },

+        getFormInputLabel: function(text) {

+            var el = this._super(text);

+            el.style.display = 'inline-block';

+            return el;

+        },

+        getFormInputField: function(type) {

+            var el = this._super(type);

+            el.style.width = '100%';

+            el.style.marginBottom = type === 'checkbox' ? '0' : '12px';

+            return el;

+        },

+        getFormInputDescription: function(text) {

+            var el = document.createElement('p');

+            el.textContent = text;

+            el.style.marginTop = '-10px';

+            el.style.fontStyle = 'italic';

+            return el;

+        },

+        getIndentedPanel: function() {

+            var el = document.createElement('div');

+            el.className = 'panel';

+            el.style.paddingBottom = 0;

+            return el;

+        },

+        getHeaderButtonHolder: function() {

+            var el = this.getButtonHolder();

+            el.style.display = 'inline-block';

+            el.style.marginLeft = '10px';

+            el.style.verticalAlign = 'middle';

+            return el;

+        },

+        getButtonHolder: function() {

+            var el = document.createElement('div');

+            el.className = 'button-group';

+            return el;

+        },

+        getButton: function(text, icon, title) {

+            var el = this._super(text, icon, title);

+            el.className += ' small button';

+            return el;

+        },

+        addInputError: function(input, text) {

+            if (!input.group) return;

+            input.group.className += ' error';

+

+            if (!input.errmsg) {

+                input.insertAdjacentHTML('afterend', '<small class="error"></small>');

+                input.errmsg = input.parentNode.getElementsByClassName('error')[0];

+            } else {

+                input.errmsg.style.display = '';

+            }

+

+            input.errmsg.textContent = text;

+        },

+        removeInputError: function(input) {

+            if (!input.errmsg) return;

+            input.group.className = input.group.className.replace(/ error/g, '');

+            input.errmsg.style.display = 'none';

+        },

+        getProgressBar: function() {

+            var progressBar = document.createElement('div');

+            progressBar.className = 'progress';

+

+            var meter = document.createElement('span');

+            meter.className = 'meter';

+            meter.style.width = '0%';

+            progressBar.appendChild(meter);

+            return progressBar;

+        },

+        updateProgressBar: function(progressBar, progress) {

+            if (!progressBar) return;

+            progressBar.firstChild.style.width = progress + '%';

+        },

+        updateProgressBarUnknown: function(progressBar) {

+            if (!progressBar) return;

+            progressBar.firstChild.style.width = '100%';

+        }

+    });

+

+    // Foundation 3 Specific Theme

+    JSONEditor.defaults.themes.foundation3 = JSONEditor.defaults.themes.foundation.extend({

+        getHeaderButtonHolder: function() {

+            var el = this._super();

+            el.style.fontSize = '.6em';

+            return el;

+        },

+        getFormInputLabel: function(text) {

+            var el = this._super(text);

+            el.style.fontWeight = 'bold';

+            return el;

+        },

+        getTabHolder: function() {

+            var el = document.createElement('div');

+            el.className = 'row';

+            el.innerHTML = "<dl class='tabs vertical two columns'></dl><div class='tabs-content ten columns'></div>";

+            return el;

+        },

+        setGridColumnSize: function(el, size) {

+            var sizes = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve'];

+            el.className = 'columns ' + sizes[size];

+        },

+        getTab: function(text) {

+            var el = document.createElement('dd');

+            var a = document.createElement('a');

+            a.setAttribute('href', '#');

+            a.appendChild(text);

+            el.appendChild(a);

+            return el;

+        },

+        getTabContentHolder: function(tab_holder) {

+            return tab_holder.children[1];

+        },

+        getTabContent: function() {

+            var el = document.createElement('div');

+            el.className = 'content active';

+            el.style.paddingLeft = '5px';

+            return el;

+        },

+        markTabActive: function(tab) {

+            tab.className += ' active';

+        },

+        markTabInactive: function(tab) {

+            tab.className = tab.className.replace(/\s*active/g, '');

+        },

+        addTab: function(holder, tab) {

+            holder.children[0].appendChild(tab);

+        }

+    });

+

+    // Foundation 4 Specific Theme

+    JSONEditor.defaults.themes.foundation4 = JSONEditor.defaults.themes.foundation.extend({

+        getHeaderButtonHolder: function() {

+            var el = this._super();

+            el.style.fontSize = '.6em';

+            return el;

+        },

+        setGridColumnSize: function(el, size) {

+            el.className = 'columns large-' + size;

+        },

+        getFormInputDescription: function(text) {

+            var el = this._super(text);

+            el.style.fontSize = '.8rem';

+            return el;

+        },

+        getFormInputLabel: function(text) {

+            var el = this._super(text);

+            el.style.fontWeight = 'bold';

+            return el;

+        }

+    });

+

+    // Foundation 5 Specific Theme

+    JSONEditor.defaults.themes.foundation5 = JSONEditor.defaults.themes.foundation.extend({

+        getFormInputDescription: function(text) {

+            var el = this._super(text);

+            el.style.fontSize = '.8rem';

+            return el;

+        },

+        setGridColumnSize: function(el, size) {

+            el.className = 'columns medium-' + size;

+        },

+        getButton: function(text, icon, title) {

+            var el = this._super(text, icon, title);

+            el.className = el.className.replace(/\s*small/g, '') + ' tiny';

+            return el;

+        },

+        getTabHolder: function() {

+            var el = document.createElement('div');

+            el.innerHTML = "<dl class='tabs vertical'></dl><div class='tabs-content vertical'></div>";

+            return el;

+        },

+        getTab: function(text) {

+            var el = document.createElement('dd');

+            var a = document.createElement('a');

+            a.setAttribute('href', '#');

+            a.appendChild(text);

+            el.appendChild(a);

+            return el;

+        },

+        getTabContentHolder: function(tab_holder) {

+            return tab_holder.children[1];

+        },

+        getTabContent: function() {

+            var el = document.createElement('div');

+            el.className = 'content active';

+            el.style.paddingLeft = '5px';

+            return el;

+        },

+        markTabActive: function(tab) {

+            tab.className += ' active';

+        },

+        markTabInactive: function(tab) {

+            tab.className = tab.className.replace(/\s*active/g, '');

+        },

+        addTab: function(holder, tab) {

+            holder.children[0].appendChild(tab);

+        }

+    });

+

+    JSONEditor.defaults.themes.html = JSONEditor.AbstractTheme.extend({

+        getFormInputLabel: function(text) {

+            var el = this._super(text);

+            el.style.display = 'block';

+            el.style.marginBottom = '3px';

+            el.style.fontWeight = 'bold';

+            return el;

+        },

+        getFormInputDescription: function(text) {

+            var el = this._super(text);

+            el.style.fontSize = '.8em';

+            el.style.margin = 0;

+            el.style.display = 'inline-block';

+            el.style.fontStyle = 'italic';

+            return el;

+        },

+        getIndentedPanel: function() {

+            var el = this._super();

+            el.style.border = '1px solid #ddd';

+            el.style.padding = '5px';

+            el.style.margin = '5px';

+            el.style.borderRadius = '3px';

+            return el;

+        },

+        getChildEditorHolder: function() {

+            var el = this._super();

+            el.style.marginBottom = '8px';

+            return el;

+        },

+        getHeaderButtonHolder: function() {

+            var el = this.getButtonHolder();

+            el.style.display = 'inline-block';

+            el.style.marginLeft = '10px';

+            el.style.fontSize = '.8em';

+            el.style.verticalAlign = 'middle';

+            return el;

+        },

+        getTable: function() {

+            var el = this._super();

+            el.style.borderBottom = '1px solid #ccc';

+            el.style.marginBottom = '5px';

+            return el;

+        },

+        addInputError: function(input, text) {

+            input.style.borderColor = 'red';

+

+            if (!input.errmsg) {

+                var group = this.closest(input, '.form-control');

+                input.errmsg = document.createElement('div');

+                input.errmsg.setAttribute('class', 'errmsg');

+                input.errmsg.style.cssText = input.errmsg.style.cssText || {};

+                input.errmsg.style.color = 'red';

+                group.appendChild(input.errmsg);

+            } else {

+                input.errmsg.style.display = 'block';

+            }

+

+            input.errmsg.innerHTML = '';

+            input.errmsg.appendChild(document.createTextNode(text));

+        },

+        removeInputError: function(input) {

+            input.style.borderColor = '';

+            if (input.errmsg) input.errmsg.style.display = 'none';

+        },

+        getProgressBar: function() {

+            var max = 100,

+                start = 0;

+

+            var progressBar = document.createElement('progress');

+            progressBar.setAttribute('max', max);

+            progressBar.setAttribute('value', start);

+            return progressBar;

+        },

+        updateProgressBar: function(progressBar, progress) {

+            if (!progressBar) return;

+            progressBar.setAttribute('value', progress);

+        },

+        updateProgressBarUnknown: function(progressBar) {

+            if (!progressBar) return;

+            progressBar.removeAttribute('value');

+        }

+    });

+

+    JSONEditor.defaults.themes.jqueryui = JSONEditor.AbstractTheme.extend({

+        getTable: function() {

+            var el = this._super();

+            el.setAttribute('cellpadding', 5);

+            el.setAttribute('cellspacing', 0);

+            return el;

+        },

+        getTableHeaderCell: function(text) {

+            var el = this._super(text);

+            el.className = 'ui-state-active';

+            el.style.fontWeight = 'bold';

+            return el;

+        },

+        getTableCell: function() {

+            var el = this._super();

+            el.className = 'ui-widget-content';

+            return el;

+        },

+        getHeaderButtonHolder: function() {

+            var el = this.getButtonHolder();

+            el.style.marginLeft = '10px';

+            el.style.fontSize = '.6em';

+            el.style.display = 'inline-block';

+            return el;

+        },

+        getFormInputDescription: function(text) {

+            var el = this.getDescription(text);

+            el.style.marginLeft = '10px';

+            el.style.display = 'inline-block';

+            return el;

+        },

+        getFormControl: function(label, input, description) {

+            var el = this._super(label, input, description);

+            if (input.type === 'checkbox') {

+                el.style.lineHeight = '25px';

+

+                el.style.padding = '3px 0';

+            } else {

+                el.style.padding = '4px 0 8px 0';

+            }

+            return el;

+        },

+        getDescription: function(text) {

+            var el = document.createElement('span');

+            el.style.fontSize = '.8em';

+            el.style.fontStyle = 'italic';

+            el.textContent = text;

+            return el;

+        },

+        getButtonHolder: function() {

+            var el = document.createElement('div');

+            el.className = 'ui-buttonset';

+            el.style.fontSize = '.7em';

+            return el;

+        },

+        getFormInputLabel: function(text) {

+            var el = document.createElement('label');

+            el.style.fontWeight = 'bold';

+            el.style.display = 'block';

+            el.textContent = text;

+            return el;

+        },

+        getButton: function(text, icon, title) {

+            var button = document.createElement("button");

+            button.className = 'ui-button ui-widget ui-state-default ui-corner-all';

+

+            // Icon only

+            if (icon && !text) {

+                button.className += ' ui-button-icon-only';

+                icon.className += ' ui-button-icon-primary ui-icon-primary';

+                button.appendChild(icon);

+            }

+            // Icon and Text

+            else if (icon) {

+                button.className += ' ui-button-text-icon-primary';

+                icon.className += ' ui-button-icon-primary ui-icon-primary';

+                button.appendChild(icon);

+            }

+            // Text only

+            else {

+                button.className += ' ui-button-text-only';

+            }

+

+            var el = document.createElement('span');

+            el.className = 'ui-button-text';

+            el.textContent = text || title || ".";

+            button.appendChild(el);

+

+            button.setAttribute('title', title);

+

+            return button;

+        },

+        setButtonText: function(button, text, icon, title) {

+            button.innerHTML = '';

+            button.className = 'ui-button ui-widget ui-state-default ui-corner-all';

+

+            // Icon only

+            if (icon && !text) {

+                button.className += ' ui-button-icon-only';

+                icon.className += ' ui-button-icon-primary ui-icon-primary';

+                button.appendChild(icon);

+            }

+            // Icon and Text

+            else if (icon) {

+                button.className += ' ui-button-text-icon-primary';

+                icon.className += ' ui-button-icon-primary ui-icon-primary';

+                button.appendChild(icon);

+            }

+            // Text only

+            else {

+                button.className += ' ui-button-text-only';

+            }

+

+            var el = document.createElement('span');

+            el.className = 'ui-button-text';

+            el.textContent = text || title || ".";

+            button.appendChild(el);

+

+            button.setAttribute('title', title);

+        },

+        getIndentedPanel: function() {

+            var el = document.createElement('div');

+            el.className = 'ui-widget-content ui-corner-all';

+            el.style.padding = '1em 1.4em';

+            el.style.marginBottom = '20px';

+            return el;

+        },

+        afterInputReady: function(input) {

+            if (input.controls) return;

+            input.controls = this.closest(input, '.form-control');

+        },

+        addInputError: function(input, text) {

+            if (!input.controls) return;

+            if (!input.errmsg) {

+                input.errmsg = document.createElement('div');

+                input.errmsg.className = 'ui-state-error';

+                input.controls.appendChild(input.errmsg);

+            } else {

+                input.errmsg.style.display = '';

+            }

+

+            input.errmsg.textContent = text;

+        },

+        removeInputError: function(input) {

+            if (!input.errmsg) return;

+            input.errmsg.style.display = 'none';

+        },

+        markTabActive: function(tab) {

+            tab.className = tab.className.replace(/\s*ui-widget-header/g, '') + ' ui-state-active';

+        },

+        markTabInactive: function(tab) {

+            tab.className = tab.className.replace(/\s*ui-state-active/g, '') + ' ui-widget-header';

+        }

+    });

+

+    JSONEditor.AbstractIconLib = Class.extend({

+        mapping: {

+            collapse: '',

+            expand: '',

+            "delete": '',

+            edit: '',

+            add: '',

+            cancel: '',

+            save: '',

+            moveup: '',

+            movedown: ''

+        },

+        icon_prefix: '',

+        getIconClass: function(key) {

+            if (this.mapping[key]) return this.icon_prefix + this.mapping[key];

+            else return null;

+        },

+        getIcon: function(key) {

+            var iconclass = this.getIconClass(key);

+

+            if (!iconclass) return null;

+

+            var i = document.createElement('i');

+            i.className = iconclass;

+            return i;

+        }

+    });

+

+    JSONEditor.defaults.iconlibs.bootstrap2 = JSONEditor.AbstractIconLib.extend({

+        mapping: {

+            collapse: 'chevron-down',

+            expand: 'chevron-up',

+            "delete": 'trash',

+            edit: 'pencil',

+            add: 'plus',

+            cancel: 'ban-circle',

+            save: 'ok',

+            moveup: 'arrow-up',

+            movedown: 'arrow-down'

+        },

+        icon_prefix: 'icon-'

+    });

+

+    JSONEditor.defaults.iconlibs.bootstrap3 = JSONEditor.AbstractIconLib.extend({

+        mapping: {

+            collapse: 'chevron-down',

+            expand: 'chevron-right',

+            "delete": 'remove',

+            edit: 'pencil',

+            add: 'plus',

+            cancel: 'floppy-remove',

+            save: 'floppy-saved',

+            moveup: 'arrow-up',

+            movedown: 'arrow-down'

+        },

+        icon_prefix: 'glyphicon glyphicon-'

+    });

+

+    JSONEditor.defaults.iconlibs.fontawesome3 = JSONEditor.AbstractIconLib.extend({

+        mapping: {

+            collapse: 'chevron-down',

+            expand: 'chevron-right',

+            "delete": 'remove',

+            edit: 'pencil',

+            add: 'plus',

+            cancel: 'ban-circle',

+            save: 'save',

+            moveup: 'arrow-up',

+            movedown: 'arrow-down'

+        },

+        icon_prefix: 'icon-'

+    });

+

+    JSONEditor.defaults.iconlibs.fontawesome4 = JSONEditor.AbstractIconLib.extend({

+        mapping: {

+            collapse: 'caret-square-o-down',

+            expand: 'caret-square-o-right',

+            "delete": 'times',

+            edit: 'pencil',

+            add: 'plus',

+            cancel: 'ban',

+            save: 'save',

+            moveup: 'arrow-up',

+            movedown: 'arrow-down'

+        },

+        icon_prefix: 'fa fa-'

+    });

+

+    JSONEditor.defaults.iconlibs.foundation2 = JSONEditor.AbstractIconLib.extend({

+        mapping: {

+            collapse: 'minus',

+            expand: 'plus',

+            "delete": 'remove',

+            edit: 'edit',

+            add: 'add-doc',

+            cancel: 'error',

+            save: 'checkmark',

+            moveup: 'up-arrow',

+            movedown: 'down-arrow'

+        },

+        icon_prefix: 'foundicon-'

+    });

+

+    JSONEditor.defaults.iconlibs.foundation3 = JSONEditor.AbstractIconLib.extend({

+        mapping: {

+            collapse: 'minus',

+            expand: 'plus',

+            "delete": 'x',

+            edit: 'pencil',

+            add: 'page-add',

+            cancel: 'x-circle',

+            save: 'save',

+            moveup: 'arrow-up',

+            movedown: 'arrow-down'

+        },

+        icon_prefix: 'fi-'

+    });

+

+    JSONEditor.defaults.iconlibs.jqueryui = JSONEditor.AbstractIconLib.extend({

+        mapping: {

+            collapse: 'triangle-1-s',

+            expand: 'triangle-1-e',

+            "delete": 'trash',

+            edit: 'pencil',

+            add: 'plusthick',

+            cancel: 'closethick',

+            save: 'disk',

+            moveup: 'arrowthick-1-n',

+            movedown: 'arrowthick-1-s'

+        },

+        icon_prefix: 'ui-icon ui-icon-'

+    });

+

+    JSONEditor.defaults.templates["default"] = function() {

+        return {

+            compile: function(template) {

+                var matches = template.match(/{{\s*([a-zA-Z0-9\-_ \.]+)\s*}}/g);

+                var l = matches && matches.length;

+

+                // Shortcut if the template contains no variables

+                if (!l) return function() {

+                    return template;

+                };

+

+                // Pre-compute the search/replace functions

+                // This drastically speeds up template execution

+                var replacements = [];

+                var get_replacement = function(i) {

+                    var p = matches[i].replace(/[{}]+/g, '').trim().split('.');

+                    var n = p.length;

+                    var func;

+

+                    if (n > 1) {

+                        var cur;

+                        func = function(vars) {

+                            cur = vars;

+                            for (i = 0; i < n; i++) {

+                                cur = cur[p[i]];

+                                if (!cur) break;

+                            }

+                            return cur;

+                        };

+                    } else {

+                        p = p[0];

+                        func = function(vars) {

+                            return vars[p];

+                        };

+                    }

+

+                    replacements.push({

+                        s: matches[i],

+                        r: func

+                    });

+                };

+                for (var i = 0; i < l; i++) {

+                    get_replacement(i);

+                }

+

+                // The compiled function

+                return function(vars) {

+                    var ret = template + "";

+                    var r;

+                    for (i = 0; i < l; i++) {

+                        r = replacements[i];

+                        ret = ret.replace(r.s, r.r(vars));

+                    }

+                    return ret;

+                };

+            }

+        };

+    };

+

+    JSONEditor.defaults.templates.ejs = function() {

+        if (!window.EJS) return false;

+

+        return {

+            compile: function(template) {

+                var compiled = new window.EJS({

+                    text: template

+                });

+

+                return function(context) {

+                    return compiled.render(context);

+                };

+            }

+        };

+    };

+

+    JSONEditor.defaults.templates.handlebars = function() {

+        return window.Handlebars;

+    };

+

+    JSONEditor.defaults.templates.hogan = function() {

+        if (!window.Hogan) return false;

+

+        return {

+            compile: function(template) {

+                var compiled = window.Hogan.compile(template);

+                return function(context) {

+                    return compiled.render(context);

+                };

+            }

+        };

+    };

+

+    JSONEditor.defaults.templates.markup = function() {

+        if (!window.Mark || !window.Mark.up) return false;

+

+        return {

+            compile: function(template) {

+                return function(context) {

+                    return window.Mark.up(template, context);

+                };

+            }

+        };

+    };

+

+    JSONEditor.defaults.templates.mustache = function() {

+        if (!window.Mustache) return false;

+

+        return {

+            compile: function(template) {

+                return function(view) {

+                    return window.Mustache.render(template, view);

+                };

+            }

+        };

+    };

+

+    JSONEditor.defaults.templates.swig = function() {

+        return window.swig;

+    };

+

+    JSONEditor.defaults.templates.underscore = function() {

+        if (!window._) return false;

+

+        return {

+            compile: function(template) {

+                return function(context) {

+                    return window._.template(template, context);

+                };

+            }

+        };

+    };

+

+    // Set the default theme

+    JSONEditor.defaults.theme = 'html';

+

+    // Set the default template engine

+    JSONEditor.defaults.template = 'default';

+

+    // Default options when initializing JSON Editor

+    JSONEditor.defaults.options = {};

+

+    // String translate function

+    JSONEditor.defaults.translate = function(key, variables) {

+        var lang = JSONEditor.defaults.languages[JSONEditor.defaults.language];

+        if (!lang) throw "Unknown language " + JSONEditor.defaults.language;

+

+        var string = lang[key] || JSONEditor.defaults.languages[JSONEditor.defaults.default_language][key];

+

+        if (typeof string === "undefined") throw "Unknown translate string " + key;

+

+        if (variables) {

+            for (var i = 0; i < variables.length; i++) {

+                string = string.replace(new RegExp('\\{\\{' + i + '}}', 'g'), variables[i]);

+            }

+        }

+

+        return string;

+    };

+

+    // Translation strings and default languages

+    JSONEditor.defaults.default_language = 'en';

+    JSONEditor.defaults.language = JSONEditor.defaults.default_language;

+    JSONEditor.defaults.languages.en = {

+        /**

+         * When a property is not set

+         */

+        error_notset: "Property must be set",

+        /**

+         * When a string must not be empty

+         */

+        error_notempty: "Value required",

+        /**

+         * When a value is not one of the enumerated values

+         */

+        error_enum: "Value must be one of the enumerated values",

+        /**

+         * When a value doesn't validate any schema of a 'anyOf' combination

+         */

+        error_anyOf: "Value must validate against at least one of the provided schemas",

+        /**

+         * When a value doesn't validate

+         * @variables This key takes one variable: The number of schemas the value does not validate

+         */

+        error_oneOf: 'Value must validate against exactly one of the provided schemas. It currently validates against {{0}} of the schemas.',

+        /**

+         * When a value does not validate a 'not' schema

+         */

+        error_not: "Value must not validate against the provided schema",

+        /**

+         * When a value does not match any of the provided types

+         */

+        error_type_union: "Value must be one of the provided types",

+        /**

+         * When a value does not match the given type

+         * @variables This key takes one variable: The type the value should be of

+         */

+        error_type: "Value must be of type {{0}}",

+        /**

+         *  When the value validates one of the disallowed types

+         */

+        error_disallow_union: "Value must not be one of the provided disallowed types",

+        /**

+         *  When the value validates a disallowed type

+         * @variables This key takes one variable: The type the value should not be of

+         */

+        error_disallow: "Value must not be of type {{0}}",

+        /**

+         * When a value is not a multiple of or divisible by a given number

+         * @variables This key takes one variable: The number mentioned above

+         */

+        error_multipleOf: "Value must be a multiple of {{0}}",

+        /**

+         * When a value is greater than it's supposed to be (exclusive)

+         * @variables This key takes one variable: The maximum

+         */

+        error_maximum_excl: "Value must be less than {{0}}",

+        /**

+         * When a value is greater than it's supposed to be (inclusive

+         * @variables This key takes one variable: The maximum

+         */

+        error_maximum_incl: "Value must be at most {{0}}",

+        /**

+         * When a value is lesser than it's supposed to be (exclusive)

+         * @variables This key takes one variable: The minimum

+         */

+        error_minimum_excl: "Value must be greater than {{0}}",

+        /**

+         * When a value is lesser than it's supposed to be (inclusive)

+         * @variables This key takes one variable: The minimum

+         */

+        error_minimum_incl: "Value must be at least {{0}}",

+        /**

+         * When a value have too many characters

+         * @variables This key takes one variable: The maximum character count

+         */

+        error_maxLength: "Value must be at most {{0}} characters long",

+        /**

+         * When a value does not have enough characters

+         * @variables This key takes one variable: The minimum character count

+         */

+        error_minLength: "Value must be at least {{0}} characters long",

+        /**

+         * When a value does not match a given pattern

+         */

+        error_pattern: "Value must match the provided pattern",

+        /**

+         * When an array has additional items whereas it is not supposed to

+         */

+        error_additionalItems: "No additional items allowed in this array",

+        /**

+         * When there are to many items in an array

+         * @variables This key takes one variable: The maximum item count

+         */

+        error_maxItems: "Value must have at most {{0}} items",

+        /**

+         * When there are not enough items in an array

+         * @variables This key takes one variable: The minimum item count

+         */

+        error_minItems: "Value must have at least {{0}} items",

+        /**

+         * When an array is supposed to have unique items but has duplicates

+         */

+        error_uniqueItems: "Array must have unique items",

+        /**

+         * When there are too many properties in an object

+         * @variables This key takes one variable: The maximum property count

+         */

+        error_maxProperties: "Object must have at most {{0}} properties",

+        /**

+         * When there are not enough properties in an object

+         * @variables This key takes one variable: The minimum property count

+         */

+        error_minProperties: "Object must have at least {{0}} properties",

+        /**

+         * When a required property is not defined

+         * @variables This key takes one variable: The name of the missing property

+         */

+        error_required: "Object is missing the required property '{{0}}'",

+        /**

+         * When there is an additional property is set whereas there should be none

+         * @variables This key takes one variable: The name of the additional property

+         */

+        error_additional_properties: "No additional properties allowed, but property {{0}} is set",

+        /**

+         * When a dependency is not resolved

+         * @variables This key takes one variable: The name of the missing property for the dependency

+         */

+        error_dependency: "Must have property {{0}}"

+    };

+

+    // Miscellaneous Plugin Settings

+    JSONEditor.plugins = {

+        ace: {

+            theme: ''

+        },

+        epiceditor: {

+

+        },

+        sceditor: {

+

+        },

+        select2: {

+

+        },

+        selectize: {}

+    };

+

+    // Default per-editor options

+    for (var i in JSONEditor.defaults.editors) {

+        if (!JSONEditor.defaults.editors.hasOwnProperty(i)) continue;

+        JSONEditor.defaults.editors[i].options = JSONEditor.defaults.editors.options || {};

+    }

+

+    // Set the default resolvers

+    // Use "multiple" as a fall back for everything

+    JSONEditor.defaults.resolvers.unshift(function(schema) {

+        if (typeof schema.type !== "string") return "multiple";

+    });

+    // If the type is not set but properties are defined, we can infer the type is actually object

+    JSONEditor.defaults.resolvers.unshift(function(schema) {

+        // If the schema is a simple type

+        if (!schema.type && schema.properties) return "object";

+    });

+    // If the type is set and it's a basic type, use the primitive editor

+    JSONEditor.defaults.resolvers.unshift(function(schema) {

+        // If the schema is a simple type

+        if (typeof schema.type === "string") return schema.type;

+    });

+    // Boolean editors

+    JSONEditor.defaults.resolvers.unshift(function(schema) {

+        if (schema.type === 'boolean') {

+            // If explicitly set to 'checkbox', use that

+            if (schema.format === "checkbox" || (schema.options && schema.options.checkbox)) {

+                return "checkbox";

+            }

+            // Otherwise, default to select menu

+            return (JSONEditor.plugins.selectize.enable) ? 'selectize' : 'select';

+        }

+    });

+    // Use the multiple editor for schemas where the `type` is set to "any"

+    JSONEditor.defaults.resolvers.unshift(function(schema) {

+        // If the schema can be of any type

+        if (schema.type === "any") return "multiple";

+    });

+    // Editor for base64 encoded files

+    JSONEditor.defaults.resolvers.unshift(function(schema) {

+        // If the schema can be of any type

+        if (schema.type === "string" && schema.media && schema.media.binaryEncoding === "base64") {

+            return "base64";

+        }

+    });

+    // Editor for uploading files

+    JSONEditor.defaults.resolvers.unshift(function(schema) {

+        if (schema.type === "string" && schema.format === "url" && schema.options && schema.options.upload === true) {

+            if (window.FileReader) return "upload";

+        }

+    });

+    // Use the table editor for arrays with the format set to `table`

+    JSONEditor.defaults.resolvers.unshift(function(schema) {

+        // Type `array` with format set to `table`

+        if (schema.type == "array" && schema.format == "table") {

+            return "table";

+        }

+    });

+    // Use the `select` editor for dynamic enumSource enums

+    JSONEditor.defaults.resolvers.unshift(function(schema) {

+        if (schema.enumSource) return (JSONEditor.plugins.selectize.enable) ? 'selectize' : 'select';

+    });

+    // Use the `enum` or `select` editors for schemas with enumerated properties

+    JSONEditor.defaults.resolvers.unshift(function(schema) {

+        if (schema["enum"]) {

+            if (schema.type === "array" || schema.type === "object") {

+                return "enum";

+            } else if (schema.type === "number" || schema.type === "integer" || schema.type === "string") {

+                return (JSONEditor.plugins.selectize.enable) ? 'selectize' : 'select';

+            }

+        }

+    });

+    // Specialized editors for arrays of strings

+    JSONEditor.defaults.resolvers.unshift(function(schema) {

+        if (schema.type === "array" && schema.items && !(Array.isArray(schema.items)) && schema.uniqueItems && ['string', 'number', 'integer'].indexOf(schema.items.type) >= 0) {

+            // For enumerated strings, number, or integers

+            if (schema.items.enum) {

+                return 'multiselect';

+            }

+            // For non-enumerated strings (tag editor)

+            else if (JSONEditor.plugins.selectize.enable && schema.items.type === "string") {

+                return 'arraySelectize';

+            }

+        }

+    });

+    // Use the multiple editor for schemas with `oneOf` set

+    JSONEditor.defaults.resolvers.unshift(function(schema) {

+        // If this schema uses `oneOf`

+        if (schema.oneOf) return "multiple";

+    });

+

+    /**

+     * This is a small wrapper for using JSON Editor like a typical jQuery plugin.

+     */

+    (function() {

+        if (window.jQuery || window.Zepto) {

+            var $ = window.jQuery || window.Zepto;

+            $.jsoneditor = JSONEditor.defaults;

+

+            $.fn.jsoneditor = function(options) {

+                var self = this;

+                var editor = this.data('jsoneditor');

+                if (options === 'value') {

+                    if (!editor) throw "Must initialize jsoneditor before getting/setting the value";

+

+                    // Set value

+                    if (arguments.length > 1) {

+                        editor.setValue(arguments[1]);

+                    }

+                    // Get value

+                    else {

+                        return editor.getValue();

+                    }

+                } else if (options === 'validate') {

+                    if (!editor) throw "Must initialize jsoneditor before validating";

+

+                    // Validate a specific value

+                    if (arguments.length > 1) {

+                        return editor.validate(arguments[1]);

+                    }

+                    // Validate current value

+                    else {

+                        return editor.validate();

+                    }

+                } else if (options === 'destroy') {

+                    if (editor) {

+                        editor.destroy();

+                        this.data('jsoneditor', null);

+                    }

+                } else {

+                    // Destroy first

+                    if (editor) {

+                        editor.destroy();

+                    }

+

+                    // Create editor

+                    editor = new JSONEditor(this.get(0), options);

+                    this.data('jsoneditor', editor);

+

+                    // Setup event listeners

+                    editor.on('change', function() {

+                        self.trigger('change');

+                    });

+                    editor.on('ready', function() {

+                        self.trigger('ready');

+                    });

+                }

+

+                return this;

+            };

+        }

+    })();

+

+    window.JSONEditor = JSONEditor;

+})();

+

+//# sourceMappingURL=jsoneditor.js.map

diff --git a/htdocs/Libs/JSONEditor/jsoneditor.min.js b/htdocs/Libs/JSONEditor/jsoneditor.min.js
new file mode 100644
index 0000000..3d019ac
--- /dev/null
+++ b/htdocs/Libs/JSONEditor/jsoneditor.min.js
@@ -0,0 +1,11 @@
+/*! JSON Editor v0.7.22 - JSON Schema -> HTML Editor
+ * By Jeremy Dorn - https://github.com/jdorn/json-editor/
+ * Released under the MIT license
+ *
+ * Date: 2015-08-12
+ */
+!function(){var a;!function(){var b=!1,c=/xyz/.test(function(){window.postMessage("xyz")})?/\b_super\b/:/.*/;return a=function(){},a.extend=function(a){function d(){!b&&this.init&&this.init.apply(this,arguments)}var e=this.prototype;b=!0;var f=new this;b=!1;for(var g in a)f[g]="function"==typeof a[g]&&"function"==typeof e[g]&&c.test(a[g])?function(a,b){return function(){var c=this._super;this._super=e[a];var d=b.apply(this,arguments);return this._super=c,d}}(g,a[g]):a[g];return d.prototype=f,d.prototype.constructor=d,d.extend=arguments.callee,d},a}(),function(){function a(a,b){b=b||{bubbles:!1,cancelable:!1,detail:void 0};var c=document.createEvent("CustomEvent");return c.initCustomEvent(a,b.bubbles,b.cancelable,b.detail),c}a.prototype=window.Event.prototype,window.CustomEvent=a}(),function(){for(var a=0,b=["ms","moz","webkit","o"],c=0;c<b.length&&!window.requestAnimationFrame;++c)window.requestAnimationFrame=window[b[c]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[b[c]+"CancelAnimationFrame"]||window[b[c]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(b,c){var d=(new Date).getTime(),e=Math.max(0,16-(d-a)),f=window.setTimeout(function(){b(d+e)},e);return a=d+e,f}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(a){clearTimeout(a)})}(),function(){Array.isArray||(Array.isArray=function(a){return"[object Array]"===Object.prototype.toString.call(a)})}();var b=function(a){return"object"!=typeof a||a.nodeType||null!==a&&a===a.window?!1:a.constructor&&!Object.prototype.hasOwnProperty.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},c=function(a){var d,e,f;for(e=1;e<arguments.length;e++){d=arguments[e];for(f in d)d.hasOwnProperty(f)&&(d[f]&&b(d[f])?(a.hasOwnProperty(f)||(a[f]={}),c(a[f],d[f])):a[f]=d[f])}return a},d=function(a,b){if(a&&"object"==typeof a){var c;if(Array.isArray(a)||"number"==typeof a.length&&a.length>0&&a.length-1 in a){for(c=0;c<a.length;c++)if(b(c,a[c])===!1)return}else if(Object.keys){var d=Object.keys(a);for(c=0;c<d.length;c++)if(b(d[c],a[d[c]])===!1)return}else for(c in a)if(a.hasOwnProperty(c)&&b(c,a[c])===!1)return}},e=function(a,b){var c=document.createEvent("HTMLEvents");c.initEvent(b,!0,!0),a.dispatchEvent(c)},f=function(a,b){if(!(a instanceof Element))throw new Error("element should be an instance of Element");b=c({},f.defaults.options,b||{}),this.element=a,this.options=b,this.init()};f.prototype={constructor:f,init:function(){var a=this;this.ready=!1;var b=f.defaults.themes[this.options.theme||f.defaults.theme];if(!b)throw"Unknown theme "+(this.options.theme||f.defaults.theme);this.schema=this.options.schema,this.theme=new b,this.template=this.options.template,this.refs=this.options.refs||{},this.uuid=0,this.__data={};var c=f.defaults.iconlibs[this.options.iconlib||f.defaults.iconlib];c&&(this.iconlib=new c),this.root_container=this.theme.getContainer(),this.element.appendChild(this.root_container),this.translate=this.options.translate||f.defaults.translate,this._loadExternalRefs(this.schema,function(){a._getDefinitions(a.schema),a.validator=new f.Validator(a);var b=a.getEditorClass(a.schema);a.root=a.createEditor(b,{jsoneditor:a,schema:a.schema,required:!0,container:a.root_container}),a.root.preBuild(),a.root.build(),a.root.postBuild(),a.options.startval&&a.root.setValue(a.options.startval),a.validation_results=a.validator.validate(a.root.getValue()),a.root.showValidationErrors(a.validation_results),a.ready=!0,window.requestAnimationFrame(function(){a.ready&&(a.validation_results=a.validator.validate(a.root.getValue()),a.root.showValidationErrors(a.validation_results),a.trigger("ready"),a.trigger("change"))})})},getValue:function(){if(!this.ready)throw"JSON Editor not ready yet.  Listen for 'ready' event before getting the value";return this.root.getValue()},setValue:function(a){if(!this.ready)throw"JSON Editor not ready yet.  Listen for 'ready' event before setting the value";return this.root.setValue(a),this},validate:function(a){if(!this.ready)throw"JSON Editor not ready yet.  Listen for 'ready' event before validating";return 1===arguments.length?this.validator.validate(a):this.validation_results},destroy:function(){this.destroyed||this.ready&&(this.schema=null,this.options=null,this.root.destroy(),this.root=null,this.root_container=null,this.validator=null,this.validation_results=null,this.theme=null,this.iconlib=null,this.template=null,this.__data=null,this.ready=!1,this.element.innerHTML="",this.destroyed=!0)},on:function(a,b){return this.callbacks=this.callbacks||{},this.callbacks[a]=this.callbacks[a]||[],this.callbacks[a].push(b),this},off:function(a,b){if(a&&b){this.callbacks=this.callbacks||{},this.callbacks[a]=this.callbacks[a]||[];for(var c=[],d=0;d<this.callbacks[a].length;d++)this.callbacks[a][d]!==b&&c.push(this.callbacks[a][d]);this.callbacks[a]=c}else a?(this.callbacks=this.callbacks||{},this.callbacks[a]=[]):this.callbacks={};return this},trigger:function(a){if(this.callbacks&&this.callbacks[a]&&this.callbacks[a].length)for(var b=0;b<this.callbacks[a].length;b++)this.callbacks[a][b]();return this},setOption:function(a,b){if("show_errors"!==a)throw"Option "+a+" must be set during instantiation and cannot be changed later";return this.options.show_errors=b,this.onChange(),this},getEditorClass:function(a){var b;if(a=this.expandSchema(a),d(f.defaults.resolvers,function(c,d){var e=d(a);return e&&f.defaults.editors[e]?(b=e,!1):void 0}),!b)throw"Unknown editor for schema "+JSON.stringify(a);if(!f.defaults.editors[b])throw"Unknown editor "+b;return f.defaults.editors[b]},createEditor:function(a,b){return b=c({},a.options||{},b),new a(b)},onChange:function(){if(this.ready&&!this.firing_change){this.firing_change=!0;var a=this;return window.requestAnimationFrame(function(){a.firing_change=!1,a.ready&&(a.validation_results=a.validator.validate(a.root.getValue()),"never"!==a.options.show_errors?a.root.showValidationErrors(a.validation_results):a.root.showValidationErrors([]),a.trigger("change"))}),this}},compileTemplate:function(a,b){b=b||f.defaults.template;var c;if("string"==typeof b){if(!f.defaults.templates[b])throw"Unknown template engine "+b;if(c=f.defaults.templates[b](),!c)throw"Template engine "+b+" missing required library."}else c=b;if(!c)throw"No template engine set";if(!c.compile)throw"Invalid template engine set";return c.compile(a)},_data:function(a,b,c){if(3!==arguments.length)return a.hasAttribute("data-jsoneditor-"+b)?this.__data[a.getAttribute("data-jsoneditor-"+b)]:null;var d;a.hasAttribute("data-jsoneditor-"+b)?d=a.getAttribute("data-jsoneditor-"+b):(d=this.uuid++,a.setAttribute("data-jsoneditor-"+b,d)),this.__data[d]=c},registerEditor:function(a){return this.editors=this.editors||{},this.editors[a.path]=a,this},unregisterEditor:function(a){return this.editors=this.editors||{},this.editors[a.path]=null,this},getEditor:function(a){return this.editors?this.editors[a]:void 0},watch:function(a,b){return this.watchlist=this.watchlist||{},this.watchlist[a]=this.watchlist[a]||[],this.watchlist[a].push(b),this},unwatch:function(a,b){if(!this.watchlist||!this.watchlist[a])return this;if(!b)return this.watchlist[a]=null,this;for(var c=[],d=0;d<this.watchlist[a].length;d++)this.watchlist[a][d]!==b&&c.push(this.watchlist[a][d]);return this.watchlist[a]=c.length?c:null,this},notifyWatchers:function(a){if(!this.watchlist||!this.watchlist[a])return this;for(var b=0;b<this.watchlist[a].length;b++)this.watchlist[a][b]()},isEnabled:function(){return!this.root||this.root.isEnabled()},enable:function(){this.root.enable()},disable:function(){this.root.disable()},_getDefinitions:function(a,b){if(b=b||"#/definitions/",a.definitions)for(var c in a.definitions)a.definitions.hasOwnProperty(c)&&(this.refs[b+c]=a.definitions[c],a.definitions[c].definitions&&this._getDefinitions(a.definitions[c],b+c+"/definitions/"))},_getExternalRefs:function(a){var b={},c=function(a){for(var c in a)a.hasOwnProperty(c)&&(b[c]=!0)};a.$ref&&"object"!=typeof a.$ref&&"#"!==a.$ref.substr(0,1)&&!this.refs[a.$ref]&&(b[a.$ref]=!0);for(var d in a)if(a.hasOwnProperty(d))if(a[d]&&"object"==typeof a[d]&&Array.isArray(a[d]))for(var e=0;e<a[d].length;e++)"object"==typeof a[d][e]&&c(this._getExternalRefs(a[d][e]));else a[d]&&"object"==typeof a[d]&&c(this._getExternalRefs(a[d]));return b},_loadExternalRefs:function(a,b){var c=this,e=this._getExternalRefs(a),f=0,g=0,h=!1;d(e,function(a){if(!c.refs[a]){if(!c.options.ajax)throw"Must set ajax option to true to load external ref "+a;c.refs[a]="loading",g++;var d=new XMLHttpRequest;d.open("GET",a,!0),d.onreadystatechange=function(){if(4==d.readyState){if(200!==d.status)throw window.console.log(d),"Failed to fetch ref via ajax- "+a;var e;try{e=JSON.parse(d.responseText)}catch(i){throw window.console.log(i),"Failed to parse external ref "+a}if(!e||"object"!=typeof e)throw"External ref does not contain a valid schema - "+a;c.refs[a]=e,c._loadExternalRefs(e,function(){f++,f>=g&&!h&&(h=!0,b())})}},d.send()}}),g||b()},expandRefs:function(a){for(a=c({},a);a.$ref;){var b=a.$ref;delete a.$ref,this.refs[b]||(b=decodeURIComponent(b)),a=this.extendSchemas(a,this.refs[b])}return a},expandSchema:function(a){var b,e=this,f=c({},a);if("object"==typeof a.type&&(Array.isArray(a.type)?d(a.type,function(b,c){"object"==typeof c&&(a.type[b]=e.expandSchema(c))}):a.type=e.expandSchema(a.type)),"object"==typeof a.disallow&&(Array.isArray(a.disallow)?d(a.disallow,function(b,c){"object"==typeof c&&(a.disallow[b]=e.expandSchema(c))}):a.disallow=e.expandSchema(a.disallow)),a.anyOf&&d(a.anyOf,function(b,c){a.anyOf[b]=e.expandSchema(c)}),a.dependencies&&d(a.dependencies,function(b,c){"object"!=typeof c||Array.isArray(c)||(a.dependencies[b]=e.expandSchema(c))}),a.not&&(a.not=this.expandSchema(a.not)),a.allOf){for(b=0;b<a.allOf.length;b++)f=this.extendSchemas(f,this.expandSchema(a.allOf[b]));delete f.allOf}if(a["extends"]){if(Array.isArray(a["extends"]))for(b=0;b<a["extends"].length;b++)f=this.extendSchemas(f,this.expandSchema(a["extends"][b]));else f=this.extendSchemas(f,this.expandSchema(a["extends"]));delete f["extends"]}if(a.oneOf){var g=c({},f);for(delete g.oneOf,b=0;b<a.oneOf.length;b++)f.oneOf[b]=this.extendSchemas(this.expandSchema(a.oneOf[b]),g)}return this.expandRefs(f)},extendSchemas:function(a,b){a=c({},a),b=c({},b);var e=this,f={};return d(a,function(a,c){"undefined"!=typeof b[a]?"required"===a&&"object"==typeof c&&Array.isArray(c)?f.required=c.concat(b[a]).reduce(function(a,b){return a.indexOf(b)<0&&a.push(b),a},[]):"type"!==a||"string"!=typeof c&&!Array.isArray(c)?"object"==typeof c&&Array.isArray(c)?f[a]=c.filter(function(c){return-1!==b[a].indexOf(c)}):"object"==typeof c&&null!==c?f[a]=e.extendSchemas(c,b[a]):f[a]=c:("string"==typeof c&&(c=[c]),"string"==typeof b.type&&(b.type=[b.type]),f.type=c.filter(function(a){return-1!==b.type.indexOf(a)}),1===f.type.length&&"string"==typeof f.type[0]&&(f.type=f.type[0])):f[a]=c}),d(b,function(b,c){"undefined"==typeof a[b]&&(f[b]=c)}),f}},f.defaults={themes:{},templates:{},iconlibs:{},editors:{},languages:{},resolvers:[],custom_validators:[]},f.Validator=a.extend({init:function(a,b){this.jsoneditor=a,this.schema=b||this.jsoneditor.schema,this.options={},this.translate=this.jsoneditor.translate||f.defaults.translate},validate:function(a){return this._validateSchema(this.schema,a)},_validateSchema:function(a,b,e){var g,h,i,j=this,k=[],l=JSON.stringify(b);if(e=e||"root",a=c({},this.jsoneditor.expandRefs(a)),a.required&&a.required===!0){if("undefined"==typeof b)return k.push({path:e,property:"required",message:this.translate("error_notset")}),k}else if("undefined"==typeof b){if(!this.jsoneditor.options.required_by_default)return k;k.push({path:e,property:"required",message:this.translate("error_notset")})}if(a["enum"]){for(g=!1,h=0;h<a["enum"].length;h++)l===JSON.stringify(a["enum"][h])&&(g=!0);g||k.push({path:e,property:"enum",message:this.translate("error_enum")})}if(a["extends"])for(h=0;h<a["extends"].length;h++)k=k.concat(this._validateSchema(a["extends"][h],b,e));if(a.allOf)for(h=0;h<a.allOf.length;h++)k=k.concat(this._validateSchema(a.allOf[h],b,e));if(a.anyOf){for(g=!1,h=0;h<a.anyOf.length;h++)if(!this._validateSchema(a.anyOf[h],b,e).length){g=!0;break}g||k.push({path:e,property:"anyOf",message:this.translate("error_anyOf")})}if(a.oneOf){g=0;var m=[];for(h=0;h<a.oneOf.length;h++){var n=this._validateSchema(a.oneOf[h],b,e);for(n.length||g++,i=0;i<n.length;i++)n[i].path=e+".oneOf["+h+"]"+n[i].path.substr(e.length);m=m.concat(n)}1!==g&&(k.push({path:e,property:"oneOf",message:this.translate("error_oneOf",[g])}),k=k.concat(m))}if(a.not&&(this._validateSchema(a.not,b,e).length||k.push({path:e,property:"not",message:this.translate("error_not")})),a.type)if(Array.isArray(a.type)){for(g=!1,h=0;h<a.type.length;h++)if(this._checkType(a.type[h],b)){g=!0;break}g||k.push({path:e,property:"type",message:this.translate("error_type_union")})}else this._checkType(a.type,b)||k.push({path:e,property:"type",message:this.translate("error_type",[a.type])});if(a.disallow)if(Array.isArray(a.disallow)){for(g=!0,h=0;h<a.disallow.length;h++)if(this._checkType(a.disallow[h],b)){g=!1;break}g||k.push({path:e,property:"disallow",message:this.translate("error_disallow_union")})}else this._checkType(a.disallow,b)&&k.push({path:e,property:"disallow",message:this.translate("error_disallow",[a.disallow])});if("number"==typeof b)(a.multipleOf||a.divisibleBy)&&(g=b/(a.multipleOf||a.divisibleBy),g!==Math.floor(g)&&k.push({path:e,property:a.multipleOf?"multipleOf":"divisibleBy",message:this.translate("error_multipleOf",[a.multipleOf||a.divisibleBy])})),a.hasOwnProperty("maximum")&&(a.exclusiveMaximum&&b>=a.maximum?k.push({path:e,property:"maximum",message:this.translate("error_maximum_excl",[a.maximum])}):!a.exclusiveMaximum&&b>a.maximum&&k.push({path:e,property:"maximum",message:this.translate("error_maximum_incl",[a.maximum])})),a.hasOwnProperty("minimum")&&(a.exclusiveMinimum&&b<=a.minimum?k.push({path:e,property:"minimum",message:this.translate("error_minimum_excl",[a.minimum])}):!a.exclusiveMinimum&&b<a.minimum&&k.push({path:e,property:"minimum",message:this.translate("error_minimum_incl",[a.minimum])}));else if("string"==typeof b)a.maxLength&&(b+"").length>a.maxLength&&k.push({path:e,property:"maxLength",message:this.translate("error_maxLength",[a.maxLength])}),a.minLength&&(b+"").length<a.minLength&&k.push({path:e,property:"minLength",message:this.translate(1===a.minLength?"error_notempty":"error_minLength",[a.minLength])}),a.pattern&&(new RegExp(a.pattern).test(b)||k.push({path:e,property:"pattern",message:this.translate("error_pattern")}));else if("object"==typeof b&&null!==b&&Array.isArray(b)){if(a.items)if(Array.isArray(a.items))for(h=0;h<b.length;h++)if(a.items[h])k=k.concat(this._validateSchema(a.items[h],b[h],e+"."+h));else{if(a.additionalItems===!0)break;if(!a.additionalItems){if(a.additionalItems===!1){k.push({path:e,property:"additionalItems",message:this.translate("error_additionalItems")});break}break}k=k.concat(this._validateSchema(a.additionalItems,b[h],e+"."+h))}else for(h=0;h<b.length;h++)k=k.concat(this._validateSchema(a.items,b[h],e+"."+h));if(a.maxItems&&b.length>a.maxItems&&k.push({path:e,property:"maxItems",message:this.translate("error_maxItems",[a.maxItems])}),a.minItems&&b.length<a.minItems&&k.push({path:e,property:"minItems",message:this.translate("error_minItems",[a.minItems])}),a.uniqueItems){var o={};for(h=0;h<b.length;h++){if(g=JSON.stringify(b[h]),o[g]){k.push({path:e,property:"uniqueItems",message:this.translate("error_uniqueItems")});break}o[g]=!0}}}else if("object"==typeof b&&null!==b){if(a.maxProperties){g=0;for(h in b)b.hasOwnProperty(h)&&g++;g>a.maxProperties&&k.push({path:e,property:"maxProperties",message:this.translate("error_maxProperties",[a.maxProperties])})}if(a.minProperties){g=0;for(h in b)b.hasOwnProperty(h)&&g++;g<a.minProperties&&k.push({path:e,property:"minProperties",message:this.translate("error_minProperties",[a.minProperties])})}if(a.required&&Array.isArray(a.required))for(h=0;h<a.required.length;h++)"undefined"==typeof b[a.required[h]]&&k.push({path:e,property:"required",message:this.translate("error_required",[a.required[h]])});var p={};if(a.properties)for(h in a.properties)a.properties.hasOwnProperty(h)&&(p[h]=!0,k=k.concat(this._validateSchema(a.properties[h],b[h],e+"."+h)));if(a.patternProperties)for(h in a.patternProperties)if(a.patternProperties.hasOwnProperty(h)){var q=new RegExp(h);for(i in b)b.hasOwnProperty(i)&&q.test(i)&&(p[i]=!0,k=k.concat(this._validateSchema(a.patternProperties[h],b[i],e+"."+i)))}if("undefined"!=typeof a.additionalProperties||!this.jsoneditor.options.no_additional_properties||a.oneOf||a.anyOf||(a.additionalProperties=!1),"undefined"!=typeof a.additionalProperties)for(h in b)if(b.hasOwnProperty(h)&&!p[h]){if(!a.additionalProperties){k.push({path:e,property:"additionalProperties",message:this.translate("error_additional_properties",[h])});break}if(a.additionalProperties===!0)break;k=k.concat(this._validateSchema(a.additionalProperties,b[h],e+"."+h))}if(a.dependencies)for(h in a.dependencies)if(a.dependencies.hasOwnProperty(h)&&"undefined"!=typeof b[h])if(Array.isArray(a.dependencies[h]))for(i=0;i<a.dependencies[h].length;i++)"undefined"==typeof b[a.dependencies[h][i]]&&k.push({path:e,property:"dependencies",message:this.translate("error_dependency",[a.dependencies[h][i]])});else k=k.concat(this._validateSchema(a.dependencies[h],b,e))}return d(f.defaults.custom_validators,function(c,d){k=k.concat(d.call(j,a,b,e))}),k},_checkType:function(a,b){return"string"==typeof a?"string"===a?"string"==typeof b:"number"===a?"number"==typeof b:"integer"===a?"number"==typeof b&&b===Math.floor(b):"boolean"===a?"boolean"==typeof b:"array"===a?Array.isArray(b):"object"===a?null!==b&&!Array.isArray(b)&&"object"==typeof b:"null"===a?null===b:!0:!this._validateSchema(a,b).length}}),f.AbstractEditor=a.extend({onChildEditorChange:function(a){this.onChange(!0)},notify:function(){this.jsoneditor.notifyWatchers(this.path)},change:function(){this.parent?this.parent.onChildEditorChange(this):this.jsoneditor.onChange()},onChange:function(a){this.notify(),this.watch_listener&&this.watch_listener(),a&&this.change()},register:function(){this.jsoneditor.registerEditor(this),this.onChange()},unregister:function(){this.jsoneditor&&this.jsoneditor.unregisterEditor(this)},getNumColumns:function(){return 12},init:function(a){this.jsoneditor=a.jsoneditor,this.theme=this.jsoneditor.theme,this.template_engine=this.jsoneditor.template,this.iconlib=this.jsoneditor.iconlib,this.original_schema=a.schema,this.schema=this.jsoneditor.expandSchema(this.original_schema),this.options=c({},this.options||{},a.schema.options||{},a),a.path||this.schema.id||(this.schema.id="root"),this.path=a.path||"root",this.formname=a.formname||this.path.replace(/\.([^.]+)/g,"[$1]"),this.jsoneditor.options.form_name_root&&(this.formname=this.formname.replace(/^root\[/,this.jsoneditor.options.form_name_root+"[")),this.key=this.path.split(".").pop(),this.parent=a.parent,this.link_watchers=[],a.container&&this.setContainer(a.container)},setContainer:function(a){this.container=a,this.schema.id&&this.container.setAttribute("data-schemaid",this.schema.id),this.schema.type&&"string"==typeof this.schema.type&&this.container.setAttribute("data-schematype",this.schema.type),this.container.setAttribute("data-schemapath",this.path)},preBuild:function(){},build:function(){},postBuild:function(){this.setupWatchListeners(),this.addLinks(),this.setValue(this.getDefault(),!0),this.updateHeaderText(),this.register(),this.onWatchedFieldChange()},setupWatchListeners:function(){var a=this;if(this.watched={},this.schema.vars&&(this.schema.watch=this.schema.vars),this.watched_values={},this.watch_listener=function(){a.refreshWatchedFieldValues()&&a.onWatchedFieldChange()},this.register(),this.schema.hasOwnProperty("watch")){var b,c,d,e,f;for(var g in this.schema.watch)if(this.schema.watch.hasOwnProperty(g)){if(b=this.schema.watch[g],Array.isArray(b)?c=[b[0]].concat(b[1].split(".")):(c=b.split("."),a.theme.closest(a.container,'[data-schemaid="'+c[0]+'"]')||c.unshift("#")),d=c.shift(),"#"===d&&(d=a.jsoneditor.schema.id||"root"),e=a.theme.closest(a.container,'[data-schemaid="'+d+'"]'),!e)throw"Could not find ancestor node with id "+d;f=e.getAttribute("data-schemapath")+"."+c.join("."),a.jsoneditor.watch(f,a.watch_listener),a.watched[g]=f}}this.schema.headerTemplate&&(this.header_template=this.jsoneditor.compileTemplate(this.schema.headerTemplate,this.template_engine))},addLinks:function(){if(!this.no_link_holder&&(this.link_holder=this.theme.getLinksHolder(),this.container.appendChild(this.link_holder),this.schema.links))for(var a=0;a<this.schema.links.length;a++)this.addLink(this.getLink(this.schema.links[a]))},getButton:function(a,b,c){var d="json-editor-btn-"+b;b=this.iconlib?this.iconlib.getIcon(b):null,!b&&c&&(a=c,c=null);var e=this.theme.getButton(a,b,c);return e.className+=" "+d+" ",e},setButtonText:function(a,b,c,d){return c=this.iconlib?this.iconlib.getIcon(c):null,!c&&d&&(b=d,d=null),this.theme.setButtonText(a,b,c,d)},addLink:function(a){this.link_holder&&this.link_holder.appendChild(a)},getLink:function(a){var b,c,d=a.mediaType||"application/javascript",e=d.split("/")[0],f=this.jsoneditor.compileTemplate(a.href,this.template_engine);if("image"===e){b=this.theme.getBlockLinkHolder(),c=document.createElement("a"),c.setAttribute("target","_blank");var g=document.createElement("img");this.theme.createImageLink(b,c,g),this.link_watchers.push(function(b){var d=f(b);c.setAttribute("href",d),c.setAttribute("title",a.rel||d),g.setAttribute("src",d)})}else if(["audio","video"].indexOf(e)>=0){b=this.theme.getBlockLinkHolder(),c=this.theme.getBlockLink(),c.setAttribute("target","_blank");var h=document.createElement(e);h.setAttribute("controls","controls"),this.theme.createMediaLink(b,c,h),this.link_watchers.push(function(b){var d=f(b);c.setAttribute("href",d),c.textContent=a.rel||d,h.setAttribute("src",d)})}else b=this.theme.getBlockLink(),b.setAttribute("target","_blank"),b.textContent=a.rel,this.link_watchers.push(function(c){var d=f(c);b.setAttribute("href",d),b.textContent=a.rel||d});return b},refreshWatchedFieldValues:function(){if(this.watched_values){var a={},b=!1,c=this;if(this.watched){var d,e;for(var f in this.watched)this.watched.hasOwnProperty(f)&&(e=c.jsoneditor.getEditor(this.watched[f]),d=e?e.getValue():null,c.watched_values[f]!==d&&(b=!0),a[f]=d)}return a.self=this.getValue(),this.watched_values.self!==a.self&&(b=!0),this.watched_values=a,b}},getWatchedFieldValues:function(){return this.watched_values},updateHeaderText:function(){if(this.header)if(this.header.children.length){for(var a=0;a<this.header.childNodes.length;a++)if(3===this.header.childNodes[a].nodeType){this.header.childNodes[a].nodeValue=this.getHeaderText();break}}else this.header.textContent=this.getHeaderText()},getHeaderText:function(a){return this.header_text?this.header_text:a?this.schema.title:this.getTitle()},onWatchedFieldChange:function(){var a;if(this.header_template){a=c(this.getWatchedFieldValues(),{key:this.key,i:this.key,i0:1*this.key,i1:1*this.key+1,title:this.getTitle()});var b=this.header_template(a);b!==this.header_text&&(this.header_text=b,this.updateHeaderText(),this.notify())}if(this.link_watchers.length){a=this.getWatchedFieldValues();for(var d=0;d<this.link_watchers.length;d++)this.link_watchers[d](a)}},setValue:function(a){this.value=a},getValue:function(){return this.value},refreshValue:function(){},getChildEditors:function(){return!1},destroy:function(){var a=this;this.unregister(this),d(this.watched,function(b,c){a.jsoneditor.unwatch(c,a.watch_listener)}),this.watched=null,this.watched_values=null,this.watch_listener=null,this.header_text=null,this.header_template=null,this.value=null,this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container),this.container=null,this.jsoneditor=null,this.schema=null,this.path=null,this.key=null,this.parent=null},getDefault:function(){if(this.schema["default"])return this.schema["default"];if(this.schema["enum"])return this.schema["enum"][0];var a=this.schema.type||this.schema.oneOf;if(a&&Array.isArray(a)&&(a=a[0]),a&&"object"==typeof a&&(a=a.type),a&&Array.isArray(a)&&(a=a[0]),"string"==typeof a){if("number"===a)return 0;if("boolean"===a)return!1;if("integer"===a)return 0;if("string"===a)return"";if("object"===a)return{};if("array"===a)return[]}return null},getTitle:function(){return this.schema.title||this.key},enable:function(){this.disabled=!1},disable:function(){this.disabled=!0},isEnabled:function(){return!this.disabled},isRequired:function(){return"boolean"==typeof this.schema.required?this.schema.required:this.parent&&this.parent.schema&&Array.isArray(this.parent.schema.required)?this.parent.schema.required.indexOf(this.key)>-1:this.jsoneditor.options.required_by_default?!0:!1},getDisplayText:function(a){var b=[],c={};d(a,function(a,b){b.title&&(c[b.title]=c[b.title]||0,c[b.title]++),b.description&&(c[b.description]=c[b.description]||0,c[b.description]++),b.format&&(c[b.format]=c[b.format]||0,c[b.format]++),b.type&&(c[b.type]=c[b.type]||0,c[b.type]++)}),d(a,function(a,d){var e;e="string"==typeof d?d:d.title&&c[d.title]<=1?d.title:d.format&&c[d.format]<=1?d.format:d.type&&c[d.type]<=1?d.type:d.description&&c[d.description]<=1?d.descripton:d.title?d.title:d.format?d.format:d.type?d.type:d.description?d.description:JSON.stringify(d).length<50?JSON.stringify(d):"type",b.push(e)});var e={};return d(b,function(a,d){e[d]=e[d]||0,e[d]++,c[d]>1&&(b[a]=d+" "+e[d])}),b},getOption:function(a){try{throw"getOption is deprecated"}catch(b){window.console.error(b)}return this.options[a]},showValidationErrors:function(a){}}),f.defaults.editors["null"]=f.AbstractEditor.extend({getValue:function(){return null},setValue:function(){this.onChange()},getNumColumns:function(){return 2}}),f.defaults.editors.string=f.AbstractEditor.extend({register:function(){this._super(),this.input&&this.input.setAttribute("name",this.formname)},unregister:function(){this._super(),this.input&&this.input.removeAttribute("name")},setValue:function(a,b,c){if((!this.template||c)&&(null===a||"undefined"==typeof a?a="":"object"==typeof a?a=JSON.stringify(a):"string"!=typeof a&&(a=""+a),a!==this.serialized)){var d=this.sanitize(a);if(this.input.value!==d){this.input.value=d,this.sceditor_instance?this.sceditor_instance.val(d):this.epiceditor?this.epiceditor.importFile(null,d):this.ace_editor&&this.ace_editor.setValue(d);var e=c||this.getValue()!==a;this.refreshValue(),b?this.is_dirty=!1:"change"===this.jsoneditor.options.show_errors&&(this.is_dirty=!0),this.adjust_height&&this.adjust_height(this.input),this.onChange(e)}}},getNumColumns:function(){var a,b=Math.ceil(Math.max(this.getTitle().length,this.schema.maxLength||0,this.schema.minLength||0)/5);return a="textarea"===this.input_type?6:["text","email"].indexOf(this.input_type)>=0?4:2,Math.min(12,Math.max(b,a))},build:function(){var a=this;if(this.options.compact||(this.header=this.label=this.theme.getFormInputLabel(this.getTitle())),this.schema.description&&(this.description=this.theme.getFormInputDescription(this.schema.description)),this.format=this.schema.format,!this.format&&this.schema.media&&this.schema.media.type&&(this.format=this.schema.media.type.replace(/(^(application|text)\/(x-)?(script\.)?)|(-source$)/g,"")),!this.format&&this.options.default_format&&(this.format=this.options.default_format),this.options.format&&(this.format=this.options.format),this.format)if("textarea"===this.format)this.input_type="textarea",this.input=this.theme.getTextareaInput();else if("range"===this.format){this.input_type="range";var b=this.schema.minimum||0,c=this.schema.maximum||Math.max(100,b+1),d=1;this.schema.multipleOf&&(b%this.schema.multipleOf&&(b=Math.ceil(b/this.schema.multipleOf)*this.schema.multipleOf),c%this.schema.multipleOf&&(c=Math.floor(c/this.schema.multipleOf)*this.schema.multipleOf),d=this.schema.multipleOf),this.input=this.theme.getRangeInput(b,c,d)}else["actionscript","batchfile","bbcode","c","c++","cpp","coffee","csharp","css","dart","django","ejs","erlang","golang","handlebars","haskell","haxe","html","ini","jade","java","javascript","json","less","lisp","lua","makefile","markdown","matlab","mysql","objectivec","pascal","perl","pgsql","php","python","r","ruby","sass","scala","scss","smarty","sql","stylus","svg","twig","vbscript","xml","yaml"].indexOf(this.format)>=0?(this.input_type=this.format,this.source_code=!0,this.input=this.theme.getTextareaInput()):(this.input_type=this.format,this.input=this.theme.getFormInputField(this.input_type));else this.input_type="text",this.input=this.theme.getFormInputField(this.input_type);"undefined"!=typeof this.schema.maxLength&&this.input.setAttribute("maxlength",this.schema.maxLength),"undefined"!=typeof this.schema.pattern?this.input.setAttribute("pattern",this.schema.pattern):"undefined"!=typeof this.schema.minLength&&this.input.setAttribute("pattern",".{"+this.schema.minLength+",}"),this.options.compact?this.container.className+=" compact":this.options.input_width&&(this.input.style.width=this.options.input_width),(this.schema.readOnly||this.schema.readonly||this.schema.template)&&(this.always_disabled=!0,this.input.disabled=!0),this.input.addEventListener("change",function(b){if(b.preventDefault(),b.stopPropagation(),a.schema.template)return void(this.value=a.value);var c=this.value,d=a.sanitize(c);c!==d&&(this.value=d),a.is_dirty=!0,a.refreshValue(),a.onChange(!0)}),this.options.input_height&&(this.input.style.height=this.options.input_height),this.options.expand_height&&(this.adjust_height=function(a){if(a){var b,c=a.offsetHeight;if(a.offsetHeight<a.scrollHeight)for(b=0;a.offsetHeight<a.scrollHeight+3&&!(b>100);)b++,c++,a.style.height=c+"px";else{for(b=0;a.offsetHeight>=a.scrollHeight+3&&!(b>100);)b++,c--,a.style.height=c+"px";a.style.height=c+1+"px"}}},this.input.addEventListener("keyup",function(b){a.adjust_height(this)}),this.input.addEventListener("change",function(b){a.adjust_height(this)}),this.adjust_height()),this.format&&this.input.setAttribute("data-schemaformat",this.format),this.control=this.theme.getFormControl(this.label,this.input,this.description),this.container.appendChild(this.control),window.requestAnimationFrame(function(){a.input.parentNode&&a.afterInputReady(),a.adjust_height&&a.adjust_height(a.input)}),this.schema.template?(this.template=this.jsoneditor.compileTemplate(this.schema.template,this.template_engine),this.refreshValue()):this.refreshValue()},enable:function(){this.always_disabled||(this.input.disabled=!1),this._super()},disable:function(){this.input.disabled=!0,this._super()},afterInputReady:function(){var a,b=this;if(this.source_code)if(this.options.wysiwyg&&["html","bbcode"].indexOf(this.input_type)>=0&&window.jQuery&&window.jQuery.fn&&window.jQuery.fn.sceditor)a=c({},{plugins:"html"===b.input_type?"xhtml":"bbcode",emoticonsEnabled:!1,width:"100%",height:300},f.plugins.sceditor,b.options.sceditor_options||{}),window.jQuery(b.input).sceditor(a),b.sceditor_instance=window.jQuery(b.input).sceditor("instance"),b.sceditor_instance.blur(function(){var a=window.jQuery("<div>"+b.sceditor_instance.val()+"</div>");window.jQuery("#sceditor-start-marker,#sceditor-end-marker,.sceditor-nlf",a).remove(),b.input.value=a.html(),b.value=b.input.value,b.is_dirty=!0,b.onChange(!0)});else if("markdown"===this.input_type&&window.EpicEditor)this.epiceditor_container=document.createElement("div"),this.input.parentNode.insertBefore(this.epiceditor_container,this.input),this.input.style.display="none",a=c({},f.plugins.epiceditor,{container:this.epiceditor_container,clientSideStorage:!1}),this.epiceditor=new window.EpicEditor(a).load(),this.epiceditor.importFile(null,this.getValue()),this.epiceditor.on("update",function(){var a=b.epiceditor.exportFile();b.input.value=a,b.value=a,b.is_dirty=!0,b.onChange(!0)});else if(window.ace){
+var d=this.input_type;("cpp"===d||"c++"===d||"c"===d)&&(d="c_cpp"),this.ace_container=document.createElement("div"),this.ace_container.style.width="100%",this.ace_container.style.position="relative",this.ace_container.style.height="400px",this.input.parentNode.insertBefore(this.ace_container,this.input),this.input.style.display="none",this.ace_editor=window.ace.edit(this.ace_container),this.ace_editor.setValue(this.getValue()),f.plugins.ace.theme&&this.ace_editor.setTheme("ace/theme/"+f.plugins.ace.theme),d=window.ace.require("ace/mode/"+d),d&&this.ace_editor.getSession().setMode(new d.Mode),this.ace_editor.on("change",function(){var a=b.ace_editor.getValue();b.input.value=a,b.refreshValue(),b.is_dirty=!0,b.onChange(!0)})}b.theme.afterInputReady(b.input)},refreshValue:function(){this.value=this.input.value,"string"!=typeof this.value&&(this.value=""),this.serialized=this.value},destroy:function(){this.sceditor_instance?this.sceditor_instance.destroy():this.epiceditor?this.epiceditor.unload():this.ace_editor&&this.ace_editor.destroy(),this.template=null,this.input&&this.input.parentNode&&this.input.parentNode.removeChild(this.input),this.label&&this.label.parentNode&&this.label.parentNode.removeChild(this.label),this.description&&this.description.parentNode&&this.description.parentNode.removeChild(this.description),this._super()},sanitize:function(a){return a},onWatchedFieldChange:function(){var a;this.template&&(a=this.getWatchedFieldValues(),this.setValue(this.template(a),!1,!0)),this._super()},showValidationErrors:function(a){var b=this;if("always"===this.jsoneditor.options.show_errors);else if(!this.is_dirty&&this.previous_error_setting===this.jsoneditor.options.show_errors)return;this.previous_error_setting=this.jsoneditor.options.show_errors;var c=[];d(a,function(a,d){d.path===b.path&&c.push(d.message)}),c.length?this.theme.addInputError(this.input,c.join(". ")+"."):this.theme.removeInputError(this.input)}}),f.defaults.editors.number=f.defaults.editors.string.extend({sanitize:function(a){return(a+"").replace(/[^0-9\.\-eE]/g,"")},getNumColumns:function(){return 2},getValue:function(){return 1*this.value}}),f.defaults.editors.integer=f.defaults.editors.number.extend({sanitize:function(a){return a+="",a.replace(/[^0-9\-]/g,"")},getNumColumns:function(){return 2}}),f.defaults.editors.object=f.AbstractEditor.extend({getDefault:function(){return c({},this.schema["default"]||{})},getChildEditors:function(){return this.editors},register:function(){if(this._super(),this.editors)for(var a in this.editors)this.editors.hasOwnProperty(a)&&this.editors[a].register()},unregister:function(){if(this._super(),this.editors)for(var a in this.editors)this.editors.hasOwnProperty(a)&&this.editors[a].unregister()},getNumColumns:function(){return Math.max(Math.min(12,this.maxwidth),3)},enable:function(){if(this.editjson_button&&(this.editjson_button.disabled=!1),this.addproperty_button&&(this.addproperty_button.disabled=!1),this._super(),this.editors)for(var a in this.editors)this.editors.hasOwnProperty(a)&&this.editors[a].enable()},disable:function(){if(this.editjson_button&&(this.editjson_button.disabled=!0),this.addproperty_button&&(this.addproperty_button.disabled=!0),this.hideEditJSON(),this._super(),this.editors)for(var a in this.editors)this.editors.hasOwnProperty(a)&&this.editors[a].disable()},layoutEditors:function(){var a,b,c=this;if(this.row_container){this.property_order=Object.keys(this.editors),this.property_order=this.property_order.sort(function(a,b){var d=c.editors[a].schema.propertyOrder,e=c.editors[b].schema.propertyOrder;return"number"!=typeof d&&(d=1e3),"number"!=typeof e&&(e=1e3),d-e});var e;if("grid"===this.format){var f=[];for(d(this.property_order,function(a,b){var d=c.editors[b];if(!d.property_removed){for(var e=!1,g=d.options.hidden?0:d.options.grid_columns||d.getNumColumns(),h=d.options.hidden?0:d.container.offsetHeight,i=0;i<f.length;i++)f[i].width+g<=12&&(!h||.5*f[i].minh<h&&2*f[i].maxh>h)&&(e=i);e===!1&&(f.push({width:0,minh:999999,maxh:0,editors:[]}),e=f.length-1),f[e].editors.push({key:b,width:g,height:h}),f[e].width+=g,f[e].minh=Math.min(f[e].minh,h),f[e].maxh=Math.max(f[e].maxh,h)}}),a=0;a<f.length;a++)if(f[a].width<12){var g=!1,h=0;for(b=0;b<f[a].editors.length;b++)g===!1?g=b:f[a].editors[b].width>f[a].editors[g].width&&(g=b),f[a].editors[b].width*=12/f[a].width,f[a].editors[b].width=Math.floor(f[a].editors[b].width),h+=f[a].editors[b].width;12>h&&(f[a].editors[g].width+=12-h),f[a].width=12}if(this.layout===JSON.stringify(f))return!1;for(this.layout=JSON.stringify(f),e=document.createElement("div"),a=0;a<f.length;a++){var i=this.theme.getGridRow();for(e.appendChild(i),b=0;b<f[a].editors.length;b++){var j=f[a].editors[b].key,k=this.editors[j];k.options.hidden?k.container.style.display="none":this.theme.setGridColumnSize(k.container,f[a].editors[b].width),i.appendChild(k.container)}}}else e=document.createElement("div"),d(this.property_order,function(a,b){var d=c.editors[b];if(!d.property_removed){var f=c.theme.getGridRow();e.appendChild(f),d.options.hidden?d.container.style.display="none":c.theme.setGridColumnSize(d.container,12),f.appendChild(d.container)}});this.row_container.innerHTML="",this.row_container.appendChild(e)}},getPropertySchema:function(a){var b=this.schema.properties[a]||{};b=c({},b);var d=this.schema.properties[a]?!0:!1;if(this.schema.patternProperties)for(var e in this.schema.patternProperties)if(this.schema.patternProperties.hasOwnProperty(e)){var f=new RegExp(e);f.test(a)&&(b.allOf=b.allOf||[],b.allOf.push(this.schema.patternProperties[e]),d=!0)}return!d&&this.schema.additionalProperties&&"object"==typeof this.schema.additionalProperties&&(b=c({},this.schema.additionalProperties)),b},preBuild:function(){this._super(),this.editors={},this.cached_editors={};var a=this;if(this.format=this.options.layout||this.options.object_layout||this.schema.format||this.jsoneditor.options.object_layout||"normal",this.schema.properties=this.schema.properties||{},this.minwidth=0,this.maxwidth=0,this.options.table_row)d(this.schema.properties,function(b,c){var d=a.jsoneditor.getEditorClass(c);a.editors[b]=a.jsoneditor.createEditor(d,{jsoneditor:a.jsoneditor,schema:c,path:a.path+"."+b,parent:a,compact:!0,required:!0}),a.editors[b].preBuild();var e=a.editors[b].options.hidden?0:a.editors[b].options.grid_columns||a.editors[b].getNumColumns();a.minwidth+=e,a.maxwidth+=e}),this.no_link_holder=!0;else{if(this.options.table)throw"Not supported yet";this.defaultProperties=this.schema.defaultProperties||Object.keys(this.schema.properties),a.maxwidth+=1,d(this.defaultProperties,function(b,c){a.addObjectProperty(c,!0),a.editors[c]&&(a.minwidth=Math.max(a.minwidth,a.editors[c].options.grid_columns||a.editors[c].getNumColumns()),a.maxwidth+=a.editors[c].options.grid_columns||a.editors[c].getNumColumns())})}this.property_order=Object.keys(this.editors),this.property_order=this.property_order.sort(function(b,c){var d=a.editors[b].schema.propertyOrder,e=a.editors[c].schema.propertyOrder;return"number"!=typeof d&&(d=1e3),"number"!=typeof e&&(e=1e3),d-e})},build:function(){var a=this;if(this.options.table_row)this.editor_holder=this.container,d(this.editors,function(b,c){var d=a.theme.getTableCell();a.editor_holder.appendChild(d),c.setContainer(d),c.build(),c.postBuild(),a.editors[b].options.hidden&&(d.style.display="none"),a.editors[b].options.input_width&&(d.style.width=a.editors[b].options.input_width)});else{if(this.options.table)throw"Not supported yet";this.header=document.createElement("span"),this.header.textContent=this.getTitle(),this.title=this.theme.getHeader(this.header),this.container.appendChild(this.title),this.container.style.position="relative",this.editjson_holder=this.theme.getModal(),this.editjson_textarea=this.theme.getTextareaInput(),this.editjson_textarea.style.height="170px",this.editjson_textarea.style.width="300px",this.editjson_textarea.style.display="block",this.editjson_save=this.getButton("Save","save","Save"),this.editjson_save.addEventListener("click",function(b){b.preventDefault(),b.stopPropagation(),a.saveJSON()}),this.editjson_cancel=this.getButton("Cancel","cancel","Cancel"),this.editjson_cancel.addEventListener("click",function(b){b.preventDefault(),b.stopPropagation(),a.hideEditJSON()}),this.editjson_holder.appendChild(this.editjson_textarea),this.editjson_holder.appendChild(this.editjson_save),this.editjson_holder.appendChild(this.editjson_cancel),this.addproperty_holder=this.theme.getModal(),this.addproperty_list=document.createElement("div"),this.addproperty_list.style.width="295px",this.addproperty_list.style.maxHeight="160px",this.addproperty_list.style.padding="5px 0",this.addproperty_list.style.overflowY="auto",this.addproperty_list.style.overflowX="hidden",this.addproperty_list.style.paddingLeft="5px",this.addproperty_list.setAttribute("class","property-selector"),this.addproperty_add=this.getButton("add","add","add"),this.addproperty_input=this.theme.getFormInputField("text"),this.addproperty_input.setAttribute("placeholder","Property name..."),this.addproperty_input.style.width="220px",this.addproperty_input.style.marginBottom="0",this.addproperty_input.style.display="inline-block",this.addproperty_add.addEventListener("click",function(b){if(b.preventDefault(),b.stopPropagation(),a.addproperty_input.value){if(a.editors[a.addproperty_input.value])return void window.alert("there is already a property with that name");a.addObjectProperty(a.addproperty_input.value),a.editors[a.addproperty_input.value]&&a.editors[a.addproperty_input.value].disable(),a.onChange(!0)}}),this.addproperty_holder.appendChild(this.addproperty_list),this.addproperty_holder.appendChild(this.addproperty_input),this.addproperty_holder.appendChild(this.addproperty_add);var b=document.createElement("div");b.style.clear="both",this.addproperty_holder.appendChild(b),this.schema.description&&(this.description=this.theme.getDescription(this.schema.description),this.container.appendChild(this.description)),this.error_holder=document.createElement("div"),this.container.appendChild(this.error_holder),this.editor_holder=this.theme.getIndentedPanel(),this.editor_holder.style.paddingBottom="0",this.container.appendChild(this.editor_holder),this.row_container=this.theme.getGridContainer(),this.editor_holder.appendChild(this.row_container),d(this.editors,function(b,c){var d=a.theme.getGridColumn();a.row_container.appendChild(d),c.setContainer(d),c.build(),c.postBuild()}),this.title_controls=this.theme.getHeaderButtonHolder(),this.editjson_controls=this.theme.getHeaderButtonHolder(),this.addproperty_controls=this.theme.getHeaderButtonHolder(),this.title.appendChild(this.title_controls),this.title.appendChild(this.editjson_controls),this.title.appendChild(this.addproperty_controls),this.collapsed=!1,this.toggle_button=this.getButton("","collapse","Collapse"),this.title_controls.appendChild(this.toggle_button),this.toggle_button.addEventListener("click",function(b){b.preventDefault(),b.stopPropagation(),a.collapsed?(a.editor_holder.style.display="",a.collapsed=!1,a.setButtonText(a.toggle_button,"","collapse","Collapse")):(a.editor_holder.style.display="none",a.collapsed=!0,a.setButtonText(a.toggle_button,"","expand","Expand"))}),this.options.collapsed&&e(this.toggle_button,"click"),this.schema.options&&"undefined"!=typeof this.schema.options.disable_collapse?this.schema.options.disable_collapse&&(this.toggle_button.style.display="none"):this.jsoneditor.options.disable_collapse&&(this.toggle_button.style.display="none"),this.editjson_button=this.getButton("JSON","edit","Edit JSON"),this.editjson_button.addEventListener("click",function(b){b.preventDefault(),b.stopPropagation(),a.toggleEditJSON()}),this.editjson_controls.appendChild(this.editjson_button),this.editjson_controls.appendChild(this.editjson_holder),this.schema.options&&"undefined"!=typeof this.schema.options.disable_edit_json?this.schema.options.disable_edit_json&&(this.editjson_button.style.display="none"):this.jsoneditor.options.disable_edit_json&&(this.editjson_button.style.display="none"),this.addproperty_button=this.getButton("Properties","edit","Object Properties"),this.addproperty_button.addEventListener("click",function(b){b.preventDefault(),b.stopPropagation(),a.toggleAddProperty()}),this.addproperty_controls.appendChild(this.addproperty_button),this.addproperty_controls.appendChild(this.addproperty_holder),this.refreshAddProperties()}this.options.table_row?(this.editor_holder=this.container,d(this.property_order,function(b,c){a.editor_holder.appendChild(a.editors[c].container)})):(this.layoutEditors(),this.layoutEditors())},showEditJSON:function(){this.editjson_holder&&(this.hideAddProperty(),this.editjson_holder.style.left=this.editjson_button.offsetLeft+"px",this.editjson_holder.style.top=this.editjson_button.offsetTop+this.editjson_button.offsetHeight+"px",this.editjson_textarea.value=JSON.stringify(this.getValue(),null,2),this.disable(),this.editjson_holder.style.display="",this.editjson_button.disabled=!1,this.editing_json=!0)},hideEditJSON:function(){this.editjson_holder&&this.editing_json&&(this.editjson_holder.style.display="none",this.enable(),this.editing_json=!1)},saveJSON:function(){if(this.editjson_holder)try{var a=JSON.parse(this.editjson_textarea.value);this.setValue(a),this.hideEditJSON()}catch(b){throw window.alert("invalid JSON"),b}},toggleEditJSON:function(){this.editing_json?this.hideEditJSON():this.showEditJSON()},insertPropertyControlUsingPropertyOrder:function(a,b,c){var d;this.schema.properties[a]&&(d=this.schema.properties[a].propertyOrder),"number"!=typeof d&&(d=1e3),b.propertyOrder=d;for(var e=0;e<c.childNodes.length;e++){var f=c.childNodes[e];if(b.propertyOrder<f.propertyOrder){this.addproperty_list.insertBefore(b,f),b=null;break}}b&&this.addproperty_list.appendChild(b)},addPropertyCheckbox:function(a){var b,c,d,e,f=this;return b=f.theme.getCheckbox(),b.style.width="auto",d=this.schema.properties[a]&&this.schema.properties[a].title?this.schema.properties[a].title:a,c=f.theme.getCheckboxLabel(d),e=f.theme.getFormControl(c,b),e.style.paddingBottom=e.style.marginBottom=e.style.paddingTop=e.style.marginTop=0,e.style.height="auto",this.insertPropertyControlUsingPropertyOrder(a,e,this.addproperty_list),b.checked=a in this.editors,b.addEventListener("change",function(){b.checked?f.addObjectProperty(a):f.removeObjectProperty(a),f.onChange(!0)}),f.addproperty_checkboxes[a]=b,b},showAddProperty:function(){this.addproperty_holder&&(this.hideEditJSON(),this.addproperty_holder.style.left=this.addproperty_button.offsetLeft+"px",this.addproperty_holder.style.top=this.addproperty_button.offsetTop+this.addproperty_button.offsetHeight+"px",this.disable(),this.adding_property=!0,this.addproperty_button.disabled=!1,this.addproperty_holder.style.display="",this.refreshAddProperties())},hideAddProperty:function(){this.addproperty_holder&&this.adding_property&&(this.addproperty_holder.style.display="none",this.enable(),this.adding_property=!1)},toggleAddProperty:function(){this.adding_property?this.hideAddProperty():this.showAddProperty()},removeObjectProperty:function(a){this.editors[a]&&(this.editors[a].unregister(),delete this.editors[a],this.refreshValue(),this.layoutEditors())},addObjectProperty:function(a,b){var c=this;if(!this.editors[a]){if(this.cached_editors[a]){if(this.editors[a]=this.cached_editors[a],b)return;this.editors[a].register()}else{if(!(this.canHaveAdditionalProperties()||this.schema.properties&&this.schema.properties[a]))return;var d=c.getPropertySchema(a),e=c.jsoneditor.getEditorClass(d);if(c.editors[a]=c.jsoneditor.createEditor(e,{jsoneditor:c.jsoneditor,schema:d,path:c.path+"."+a,parent:c}),c.editors[a].preBuild(),!b){var f=c.theme.getChildEditorHolder();c.editor_holder.appendChild(f),c.editors[a].setContainer(f),c.editors[a].build(),c.editors[a].postBuild()}c.cached_editors[a]=c.editors[a]}b||(c.refreshValue(),c.layoutEditors())}},onChildEditorChange:function(a){this.refreshValue(),this._super(a)},canHaveAdditionalProperties:function(){return"boolean"==typeof this.schema.additionalProperties?this.schema.additionalProperties:!this.jsoneditor.options.no_additional_properties},destroy:function(){d(this.cached_editors,function(a,b){b.destroy()}),this.editor_holder&&(this.editor_holder.innerHTML=""),this.title&&this.title.parentNode&&this.title.parentNode.removeChild(this.title),this.error_holder&&this.error_holder.parentNode&&this.error_holder.parentNode.removeChild(this.error_holder),this.editors=null,this.cached_editors=null,this.editor_holder&&this.editor_holder.parentNode&&this.editor_holder.parentNode.removeChild(this.editor_holder),this.editor_holder=null,this._super()},getValue:function(){var a=this._super();if(this.jsoneditor.options.remove_empty_properties||this.options.remove_empty_properties)for(var b in a)a.hasOwnProperty(b)&&(a[b]||delete a[b]);return a},refreshValue:function(){this.value={};for(var a in this.editors)this.editors.hasOwnProperty(a)&&(this.value[a]=this.editors[a].getValue());this.adding_property&&this.refreshAddProperties()},refreshAddProperties:function(){if(this.options.disable_properties||this.options.disable_properties!==!1&&this.jsoneditor.options.disable_properties)return void(this.addproperty_controls.style.display="none");var a,b=!1,c=!1,d=0,e=!1;for(a in this.editors)this.editors.hasOwnProperty(a)&&d++;b=this.canHaveAdditionalProperties()&&!("undefined"!=typeof this.schema.maxProperties&&d>=this.schema.maxProperties),this.addproperty_checkboxes&&(this.addproperty_list.innerHTML=""),this.addproperty_checkboxes={};for(a in this.cached_editors)this.cached_editors.hasOwnProperty(a)&&(this.addPropertyCheckbox(a),this.isRequired(this.cached_editors[a])&&a in this.editors&&(this.addproperty_checkboxes[a].disabled=!0),"undefined"!=typeof this.schema.minProperties&&d<=this.schema.minProperties?(this.addproperty_checkboxes[a].disabled=this.addproperty_checkboxes[a].checked,this.addproperty_checkboxes[a].checked||(e=!0)):a in this.editors?(e=!0,c=!0):b||this.schema.properties.hasOwnProperty(a)?(this.addproperty_checkboxes[a].disabled=!1,e=!0):this.addproperty_checkboxes[a].disabled=!0);this.canHaveAdditionalProperties()&&(e=!0);for(a in this.schema.properties)this.schema.properties.hasOwnProperty(a)&&(this.cached_editors[a]||(e=!0,this.addPropertyCheckbox(a)));e?this.canHaveAdditionalProperties()?b?this.addproperty_add.disabled=!1:this.addproperty_add.disabled=!0:(this.addproperty_add.style.display="none",this.addproperty_input.style.display="none"):(this.hideAddProperty(),this.addproperty_controls.style.display="none")},isRequired:function(a){return"boolean"==typeof a.schema.required?a.schema.required:Array.isArray(this.schema.required)?this.schema.required.indexOf(a.key)>-1:this.jsoneditor.options.required_by_default?!0:!1},setValue:function(a,b){var c=this;a=a||{},("object"!=typeof a||Array.isArray(a))&&(a={}),d(this.cached_editors,function(d,e){"undefined"!=typeof a[d]?(c.addObjectProperty(d),e.setValue(a[d],b)):b||c.isRequired(e)?e.setValue(e.getDefault(),b):c.removeObjectProperty(d)}),d(a,function(a,d){c.cached_editors[a]||(c.addObjectProperty(a),c.editors[a]&&c.editors[a].setValue(d,b))}),this.refreshValue(),this.layoutEditors(),this.onChange()},showValidationErrors:function(a){var b=this,c=[],e=[];if(d(a,function(a,d){d.path===b.path?c.push(d):e.push(d)}),this.error_holder)if(c.length){this.error_holder.innerHTML="",this.error_holder.style.display="",d(c,function(a,c){b.error_holder.appendChild(b.theme.getErrorMessage(c.message))})}else this.error_holder.style.display="none";this.options.table_row&&(c.length?this.theme.addTableRowError(this.container):this.theme.removeTableRowError(this.container)),d(this.editors,function(a,b){b.showValidationErrors(e)})}}),f.defaults.editors.array=f.AbstractEditor.extend({getDefault:function(){return this.schema["default"]||[]},register:function(){if(this._super(),this.rows)for(var a=0;a<this.rows.length;a++)this.rows[a].register()},unregister:function(){if(this._super(),this.rows)for(var a=0;a<this.rows.length;a++)this.rows[a].unregister()},getNumColumns:function(){var a=this.getItemInfo(0);return this.tabs_holder?Math.max(Math.min(12,a.width+2),4):a.width},enable:function(){if(this.add_row_button&&(this.add_row_button.disabled=!1),this.remove_all_rows_button&&(this.remove_all_rows_button.disabled=!1),this.delete_last_row_button&&(this.delete_last_row_button.disabled=!1),this.rows)for(var a=0;a<this.rows.length;a++)this.rows[a].enable(),this.rows[a].moveup_button&&(this.rows[a].moveup_button.disabled=!1),this.rows[a].movedown_button&&(this.rows[a].movedown_button.disabled=!1),this.rows[a].delete_button&&(this.rows[a].delete_button.disabled=!1);this._super()},disable:function(){if(this.add_row_button&&(this.add_row_button.disabled=!0),this.remove_all_rows_button&&(this.remove_all_rows_button.disabled=!0),this.delete_last_row_button&&(this.delete_last_row_button.disabled=!0),this.rows)for(var a=0;a<this.rows.length;a++)this.rows[a].disable(),this.rows[a].moveup_button&&(this.rows[a].moveup_button.disabled=!0),this.rows[a].movedown_button&&(this.rows[a].movedown_button.disabled=!0),this.rows[a].delete_button&&(this.rows[a].delete_button.disabled=!0);this._super()},preBuild:function(){this._super(),this.rows=[],this.row_cache=[],this.hide_delete_buttons=this.options.disable_array_delete||this.jsoneditor.options.disable_array_delete,this.hide_move_buttons=this.options.disable_array_reorder||this.jsoneditor.options.disable_array_reorder,this.hide_add_button=this.options.disable_array_add||this.jsoneditor.options.disable_array_add},build:function(){this.options.compact?(this.panel=this.theme.getIndentedPanel(),this.container.appendChild(this.panel),this.controls=this.theme.getButtonHolder(),this.panel.appendChild(this.controls),this.row_holder=document.createElement("div"),this.panel.appendChild(this.row_holder)):(this.header=document.createElement("span"),this.header.textContent=this.getTitle(),this.title=this.theme.getHeader(this.header),this.container.appendChild(this.title),this.title_controls=this.theme.getHeaderButtonHolder(),this.title.appendChild(this.title_controls),this.schema.description&&(this.description=this.theme.getDescription(this.schema.description),this.container.appendChild(this.description)),this.error_holder=document.createElement("div"),this.container.appendChild(this.error_holder),"tabs"===this.schema.format?(this.controls=this.theme.getHeaderButtonHolder(),this.title.appendChild(this.controls),this.tabs_holder=this.theme.getTabHolder(),this.container.appendChild(this.tabs_holder),this.row_holder=this.theme.getTabContentHolder(this.tabs_holder),this.active_tab=null):(this.panel=this.theme.getIndentedPanel(),this.container.appendChild(this.panel),this.row_holder=document.createElement("div"),this.panel.appendChild(this.row_holder),this.controls=this.theme.getButtonHolder(),this.panel.appendChild(this.controls))),this.addControls()},onChildEditorChange:function(a){this.refreshValue(),this.refreshTabs(!0),this._super(a)},getItemTitle:function(){if(!this.item_title)if(this.schema.items&&!Array.isArray(this.schema.items)){var a=this.jsoneditor.expandRefs(this.schema.items);this.item_title=a.title||"item"}else this.item_title="item";return this.item_title},getItemSchema:function(a){return Array.isArray(this.schema.items)?a>=this.schema.items.length?this.schema.additionalItems===!0?{}:this.schema.additionalItems?c({},this.schema.additionalItems):void 0:c({},this.schema.items[a]):this.schema.items?c({},this.schema.items):{}},getItemInfo:function(a){var b=this.getItemSchema(a);this.item_info=this.item_info||{};var c=JSON.stringify(b);return"undefined"!=typeof this.item_info[c]?this.item_info[c]:(b=this.jsoneditor.expandRefs(b),this.item_info[c]={title:b.title||"item","default":b["default"],width:12,child_editors:b.properties||b.items},this.item_info[c])},getElementEditor:function(a){var b=this.getItemInfo(a),c=this.getItemSchema(a);c=this.jsoneditor.expandRefs(c),c.title=b.title+" "+(a+1);var d,e=this.jsoneditor.getEditorClass(c);d=this.tabs_holder?this.theme.getTabContent():b.child_editors?this.theme.getChildEditorHolder():this.theme.getIndentedPanel(),this.row_holder.appendChild(d);var f=this.jsoneditor.createEditor(e,{jsoneditor:this.jsoneditor,schema:c,container:d,path:this.path+"."+a,parent:this,required:!0});return f.preBuild(),f.build(),f.postBuild(),f.title_controls||(f.array_controls=this.theme.getButtonHolder(),d.appendChild(f.array_controls)),f},destroy:function(){this.empty(!0),this.title&&this.title.parentNode&&this.title.parentNode.removeChild(this.title),this.description&&this.description.parentNode&&this.description.parentNode.removeChild(this.description),this.row_holder&&this.row_holder.parentNode&&this.row_holder.parentNode.removeChild(this.row_holder),this.controls&&this.controls.parentNode&&this.controls.parentNode.removeChild(this.controls),this.panel&&this.panel.parentNode&&this.panel.parentNode.removeChild(this.panel),this.rows=this.row_cache=this.title=this.description=this.row_holder=this.panel=this.controls=null,this._super()},empty:function(a){if(this.rows){var b=this;d(this.rows,function(c,d){a&&(d.tab&&d.tab.parentNode&&d.tab.parentNode.removeChild(d.tab),b.destroyRow(d,!0),b.row_cache[c]=null),b.rows[c]=null}),b.rows=[],a&&(b.row_cache=[])}},destroyRow:function(a,b){var c=a.container;b?(a.destroy(),c.parentNode&&c.parentNode.removeChild(c),a.tab&&a.tab.parentNode&&a.tab.parentNode.removeChild(a.tab)):(a.tab&&(a.tab.style.display="none"),c.style.display="none",a.unregister())},getMax:function(){return Array.isArray(this.schema.items)&&this.schema.additionalItems===!1?Math.min(this.schema.items.length,this.schema.maxItems||1/0):this.schema.maxItems||1/0},refreshTabs:function(a){var b=this;d(this.rows,function(c,d){d.tab&&(a?d.tab_text.textContent=d.getHeaderText():d.tab===b.active_tab?(b.theme.markTabActive(d.tab),d.container.style.display=""):(b.theme.markTabInactive(d.tab),d.container.style.display="none"))})},setValue:function(a,b){a=a||[],Array.isArray(a)||(a=[a]);var c=JSON.stringify(a);if(c!==this.serialized){if(this.schema.minItems)for(;a.length<this.schema.minItems;)a.push(this.getItemInfo(a.length)["default"]);this.getMax()&&a.length>this.getMax()&&(a=a.slice(0,this.getMax()));var e=this;d(a,function(a,c){e.rows[a]?e.rows[a].setValue(c,b):e.row_cache[a]?(e.rows[a]=e.row_cache[a],e.rows[a].setValue(c,b),e.rows[a].container.style.display="",e.rows[a].tab&&(e.rows[a].tab.style.display=""),e.rows[a].register()):e.addRow(c,b)});for(var f=a.length;f<e.rows.length;f++)e.destroyRow(e.rows[f]),e.rows[f]=null;e.rows=e.rows.slice(0,a.length);var g=null;d(e.rows,function(a,b){return b.tab===e.active_tab?(g=b.tab,!1):void 0}),!g&&e.rows.length&&(g=e.rows[0].tab),e.active_tab=g,e.refreshValue(b),e.refreshTabs(!0),e.refreshTabs(),e.onChange()}},refreshValue:function(a){var b=this,c=this.value?this.value.length:0;if(this.value=[],d(this.rows,function(a,c){b.value[a]=c.getValue()}),c!==this.value.length||a){var e=this.schema.minItems&&this.schema.minItems>=this.rows.length;d(this.rows,function(a,c){c.movedown_button&&(a===b.rows.length-1?c.movedown_button.style.display="none":c.movedown_button.style.display=""),c.delete_button&&(e?c.delete_button.style.display="none":c.delete_button.style.display=""),b.value[a]=c.getValue()});var f=!1;this.value.length?1===this.value.length?(this.remove_all_rows_button.style.display="none",e||this.hide_delete_buttons?this.delete_last_row_button.style.display="none":(this.delete_last_row_button.style.display="",f=!0)):e||this.hide_delete_buttons?(this.delete_last_row_button.style.display="none",this.remove_all_rows_button.style.display="none"):(this.delete_last_row_button.style.display="",this.remove_all_rows_button.style.display="",f=!0):(this.delete_last_row_button.style.display="none",this.remove_all_rows_button.style.display="none"),this.getMax()&&this.getMax()<=this.rows.length||this.hide_add_button?this.add_row_button.style.display="none":(this.add_row_button.style.display="",f=!0),!this.collapsed&&f?this.controls.style.display="inline-block":this.controls.style.display="none"}},addRow:function(a,b){var c=this,e=this.rows.length;c.rows[e]=this.getElementEditor(e),c.row_cache[e]=c.rows[e],c.tabs_holder&&(c.rows[e].tab_text=document.createElement("span"),c.rows[e].tab_text.textContent=c.rows[e].getHeaderText(),c.rows[e].tab=c.theme.getTab(c.rows[e].tab_text),c.rows[e].tab.addEventListener("click",function(a){c.active_tab=c.rows[e].tab,c.refreshTabs(),a.preventDefault(),a.stopPropagation()}),c.theme.addTab(c.tabs_holder,c.rows[e].tab));var f=c.rows[e].title_controls||c.rows[e].array_controls;c.hide_delete_buttons||(c.rows[e].delete_button=this.getButton(c.getItemTitle(),"delete","Delete "+c.getItemTitle()),c.rows[e].delete_button.className+=" delete",c.rows[e].delete_button.setAttribute("data-i",e),c.rows[e].delete_button.addEventListener("click",function(a){a.preventDefault(),a.stopPropagation();var b=1*this.getAttribute("data-i"),e=c.getValue(),f=[],g=null;d(e,function(a,d){return a===b?void(c.rows[a].tab===c.active_tab&&(c.rows[a+1]?g=c.rows[a].tab:a&&(g=c.rows[a-1].tab))):void f.push(d)}),c.setValue(f),g&&(c.active_tab=g,c.refreshTabs()),c.onChange(!0)}),f&&f.appendChild(c.rows[e].delete_button)),e&&!c.hide_move_buttons&&(c.rows[e].moveup_button=this.getButton("","moveup","Move up"),c.rows[e].moveup_button.className+=" moveup",c.rows[e].moveup_button.setAttribute("data-i",e),c.rows[e].moveup_button.addEventListener("click",function(a){a.preventDefault(),a.stopPropagation();var b=1*this.getAttribute("data-i");if(!(0>=b)){var d=c.getValue(),e=d[b-1];d[b-1]=d[b],d[b]=e,c.setValue(d),c.active_tab=c.rows[b-1].tab,c.refreshTabs(),c.onChange(!0)}}),f&&f.appendChild(c.rows[e].moveup_button)),c.hide_move_buttons||(c.rows[e].movedown_button=this.getButton("","movedown","Move down"),c.rows[e].movedown_button.className+=" movedown",c.rows[e].movedown_button.setAttribute("data-i",e),c.rows[e].movedown_button.addEventListener("click",function(a){a.preventDefault(),a.stopPropagation();var b=1*this.getAttribute("data-i"),d=c.getValue();if(!(b>=d.length-1)){var e=d[b+1];d[b+1]=d[b],d[b]=e,c.setValue(d),c.active_tab=c.rows[b+1].tab,c.refreshTabs(),c.onChange(!0)}}),f&&f.appendChild(c.rows[e].movedown_button)),a&&c.rows[e].setValue(a,b),c.refreshTabs()},addControls:function(){var a=this;this.collapsed=!1,this.toggle_button=this.getButton("","collapse","Collapse"),this.title_controls.appendChild(this.toggle_button);var b=a.row_holder.style.display,c=a.controls.style.display;this.toggle_button.addEventListener("click",function(d){d.preventDefault(),d.stopPropagation(),a.collapsed?(a.collapsed=!1,a.panel&&(a.panel.style.display=""),a.row_holder.style.display=b,a.tabs_holder&&(a.tabs_holder.style.display=""),a.controls.style.display=c,a.setButtonText(this,"","collapse","Collapse")):(a.collapsed=!0,a.row_holder.style.display="none",a.tabs_holder&&(a.tabs_holder.style.display="none"),a.controls.style.display="none",a.panel&&(a.panel.style.display="none"),a.setButtonText(this,"","expand","Expand"))}),this.options.collapsed&&e(this.toggle_button,"click"),this.schema.options&&"undefined"!=typeof this.schema.options.disable_collapse?this.schema.options.disable_collapse&&(this.toggle_button.style.display="none"):this.jsoneditor.options.disable_collapse&&(this.toggle_button.style.display="none"),this.add_row_button=this.getButton(this.getItemTitle(),"add","Add "+this.getItemTitle()),this.add_row_button.addEventListener("click",function(b){b.preventDefault(),b.stopPropagation();var c=a.rows.length;a.row_cache[c]?(a.rows[c]=a.row_cache[c],a.rows[c].setValue(a.rows[c].getDefault()),a.rows[c].container.style.display="",a.rows[c].tab&&(a.rows[c].tab.style.display=""),a.rows[c].register()):a.addRow(),a.active_tab=a.rows[c].tab,a.refreshTabs(),a.refreshValue(),a.onChange(!0)}),a.controls.appendChild(this.add_row_button),this.delete_last_row_button=this.getButton("Last "+this.getItemTitle(),"delete","Delete Last "+this.getItemTitle()),
+this.delete_last_row_button.addEventListener("click",function(b){b.preventDefault(),b.stopPropagation();var c=a.getValue(),d=null;a.rows.length>1&&a.rows[a.rows.length-1].tab===a.active_tab&&(d=a.rows[a.rows.length-2].tab),c.pop(),a.setValue(c),d&&(a.active_tab=d,a.refreshTabs()),a.onChange(!0)}),a.controls.appendChild(this.delete_last_row_button),this.remove_all_rows_button=this.getButton("All","delete","Delete All"),this.remove_all_rows_button.addEventListener("click",function(b){b.preventDefault(),b.stopPropagation(),a.setValue([]),a.onChange(!0)}),a.controls.appendChild(this.remove_all_rows_button),a.tabs&&(this.add_row_button.style.width="100%",this.add_row_button.style.textAlign="left",this.add_row_button.style.marginBottom="3px",this.delete_last_row_button.style.width="100%",this.delete_last_row_button.style.textAlign="left",this.delete_last_row_button.style.marginBottom="3px",this.remove_all_rows_button.style.width="100%",this.remove_all_rows_button.style.textAlign="left",this.remove_all_rows_button.style.marginBottom="3px")},showValidationErrors:function(a){var b=this,c=[],e=[];if(d(a,function(a,d){d.path===b.path?c.push(d):e.push(d)}),this.error_holder)if(c.length){this.error_holder.innerHTML="",this.error_holder.style.display="",d(c,function(a,c){b.error_holder.appendChild(b.theme.getErrorMessage(c.message))})}else this.error_holder.style.display="none";d(this.rows,function(a,b){b.showValidationErrors(e)})}}),f.defaults.editors.table=f.defaults.editors.array.extend({register:function(){if(this._super(),this.rows)for(var a=0;a<this.rows.length;a++)this.rows[a].register()},unregister:function(){if(this._super(),this.rows)for(var a=0;a<this.rows.length;a++)this.rows[a].unregister()},getNumColumns:function(){return Math.max(Math.min(12,this.width),3)},preBuild:function(){var a=this.jsoneditor.expandRefs(this.schema.items||{});this.item_title=a.title||"row",this.item_default=a["default"]||null,this.item_has_child_editors=a.properties||a.items,this.width=12,this._super()},build:function(){var a=this;this.table=this.theme.getTable(),this.container.appendChild(this.table),this.thead=this.theme.getTableHead(),this.table.appendChild(this.thead),this.header_row=this.theme.getTableRow(),this.thead.appendChild(this.header_row),this.row_holder=this.theme.getTableBody(),this.table.appendChild(this.row_holder);var b=this.getElementEditor(0,!0);if(this.item_default=b.getDefault(),this.width=b.getNumColumns()+2,this.options.compact?(this.panel=document.createElement("div"),this.container.appendChild(this.panel)):(this.title=this.theme.getHeader(this.getTitle()),this.container.appendChild(this.title),this.title_controls=this.theme.getHeaderButtonHolder(),this.title.appendChild(this.title_controls),this.schema.description&&(this.description=this.theme.getDescription(this.schema.description),this.container.appendChild(this.description)),this.panel=this.theme.getIndentedPanel(),this.container.appendChild(this.panel),this.error_holder=document.createElement("div"),this.panel.appendChild(this.error_holder)),this.panel.appendChild(this.table),this.controls=this.theme.getButtonHolder(),this.panel.appendChild(this.controls),this.item_has_child_editors)for(var c=b.getChildEditors(),d=b.property_order||Object.keys(c),e=0;e<d.length;e++){var f=a.theme.getTableHeaderCell(c[d[e]].getTitle());c[d[e]].options.hidden&&(f.style.display="none"),a.header_row.appendChild(f)}else a.header_row.appendChild(a.theme.getTableHeaderCell(this.item_title));b.destroy(),this.row_holder.innerHTML="",this.controls_header_cell=a.theme.getTableHeaderCell(" "),a.header_row.appendChild(this.controls_header_cell),this.addControls()},onChildEditorChange:function(a){this.refreshValue(),this._super()},getItemDefault:function(){return c({},{"default":this.item_default})["default"]},getItemTitle:function(){return this.item_title},getElementEditor:function(a,b){var d=c({},this.schema.items),e=this.jsoneditor.getEditorClass(d,this.jsoneditor),f=this.row_holder.appendChild(this.theme.getTableRow()),g=f;this.item_has_child_editors||(g=this.theme.getTableCell(),f.appendChild(g));var h=this.jsoneditor.createEditor(e,{jsoneditor:this.jsoneditor,schema:d,container:g,path:this.path+"."+a,parent:this,compact:!0,table_row:!0});return h.preBuild(),b||(h.build(),h.postBuild(),h.controls_cell=f.appendChild(this.theme.getTableCell()),h.row=f,h.table_controls=this.theme.getButtonHolder(),h.controls_cell.appendChild(h.table_controls),h.table_controls.style.margin=0,h.table_controls.style.padding=0),h},destroy:function(){this.innerHTML="",this.title&&this.title.parentNode&&this.title.parentNode.removeChild(this.title),this.description&&this.description.parentNode&&this.description.parentNode.removeChild(this.description),this.row_holder&&this.row_holder.parentNode&&this.row_holder.parentNode.removeChild(this.row_holder),this.table&&this.table.parentNode&&this.table.parentNode.removeChild(this.table),this.panel&&this.panel.parentNode&&this.panel.parentNode.removeChild(this.panel),this.rows=this.title=this.description=this.row_holder=this.table=this.panel=null,this._super()},setValue:function(a,b){if(a=a||[],this.schema.minItems)for(;a.length<this.schema.minItems;)a.push(this.getItemDefault());this.schema.maxItems&&a.length>this.schema.maxItems&&(a=a.slice(0,this.schema.maxItems));var c=JSON.stringify(a);if(c!==this.serialized){var e=!1,f=this;d(a,function(a,b){f.rows[a]?f.rows[a].setValue(b):(f.addRow(b),e=!0)});for(var g=a.length;g<f.rows.length;g++){var h=f.rows[g].container;f.item_has_child_editors||f.rows[g].row.parentNode.removeChild(f.rows[g].row),f.rows[g].destroy(),h.parentNode&&h.parentNode.removeChild(h),f.rows[g]=null,e=!0}f.rows=f.rows.slice(0,a.length),f.refreshValue(),(e||b)&&f.refreshRowButtons(),f.onChange()}},refreshRowButtons:function(){var a=this,b=this.schema.minItems&&this.schema.minItems>=this.rows.length,c=!1;d(this.rows,function(d,e){e.movedown_button&&(d===a.rows.length-1?e.movedown_button.style.display="none":(c=!0,e.movedown_button.style.display="")),e.delete_button&&(b?e.delete_button.style.display="none":(c=!0,e.delete_button.style.display="")),e.moveup_button&&(c=!0)}),d(this.rows,function(a,b){c?b.controls_cell.style.display="":b.controls_cell.style.display="none"}),c?this.controls_header_cell.style.display="":this.controls_header_cell.style.display="none";var e=!1;this.value.length?1===this.value.length||this.hide_delete_buttons?(this.table.style.display="",this.remove_all_rows_button.style.display="none",b||this.hide_delete_buttons?this.delete_last_row_button.style.display="none":(this.delete_last_row_button.style.display="",e=!0)):(this.table.style.display="",b||this.hide_delete_buttons?(this.delete_last_row_button.style.display="none",this.remove_all_rows_button.style.display="none"):(this.delete_last_row_button.style.display="",this.remove_all_rows_button.style.display="",e=!0)):(this.delete_last_row_button.style.display="none",this.remove_all_rows_button.style.display="none",this.table.style.display="none"),this.schema.maxItems&&this.schema.maxItems<=this.rows.length||this.hide_add_button?this.add_row_button.style.display="none":(this.add_row_button.style.display="",e=!0),e?this.controls.style.display="":this.controls.style.display="none"},refreshValue:function(){var a=this;this.value=[],d(this.rows,function(b,c){a.value[b]=c.getValue()}),this.serialized=JSON.stringify(this.value)},addRow:function(a){var b=this,c=this.rows.length;b.rows[c]=this.getElementEditor(c);var e=b.rows[c].table_controls;this.hide_delete_buttons||(b.rows[c].delete_button=this.getButton("","delete","Delete"),b.rows[c].delete_button.className+=" delete",b.rows[c].delete_button.setAttribute("data-i",c),b.rows[c].delete_button.addEventListener("click",function(a){a.preventDefault(),a.stopPropagation();var c=1*this.getAttribute("data-i"),e=b.getValue(),f=[];d(e,function(a,b){a!==c&&f.push(b)}),b.setValue(f),b.onChange(!0)}),e.appendChild(b.rows[c].delete_button)),c&&!this.hide_move_buttons&&(b.rows[c].moveup_button=this.getButton("","moveup","Move up"),b.rows[c].moveup_button.className+=" moveup",b.rows[c].moveup_button.setAttribute("data-i",c),b.rows[c].moveup_button.addEventListener("click",function(a){a.preventDefault(),a.stopPropagation();var c=1*this.getAttribute("data-i");if(!(0>=c)){var d=b.getValue(),e=d[c-1];d[c-1]=d[c],d[c]=e,b.setValue(d),b.onChange(!0)}}),e.appendChild(b.rows[c].moveup_button)),this.hide_move_buttons||(b.rows[c].movedown_button=this.getButton("","movedown","Move down"),b.rows[c].movedown_button.className+=" movedown",b.rows[c].movedown_button.setAttribute("data-i",c),b.rows[c].movedown_button.addEventListener("click",function(a){a.preventDefault(),a.stopPropagation();var c=1*this.getAttribute("data-i"),d=b.getValue();if(!(c>=d.length-1)){var e=d[c+1];d[c+1]=d[c],d[c]=e,b.setValue(d),b.onChange(!0)}}),e.appendChild(b.rows[c].movedown_button)),a&&b.rows[c].setValue(a)},addControls:function(){var a=this;this.collapsed=!1,this.toggle_button=this.getButton("","collapse","Collapse"),this.title_controls&&(this.title_controls.appendChild(this.toggle_button),this.toggle_button.addEventListener("click",function(b){b.preventDefault(),b.stopPropagation(),a.collapsed?(a.collapsed=!1,a.panel.style.display="",a.setButtonText(this,"","collapse","Collapse")):(a.collapsed=!0,a.panel.style.display="none",a.setButtonText(this,"","expand","Expand"))}),this.options.collapsed&&e(this.toggle_button,"click"),this.schema.options&&"undefined"!=typeof this.schema.options.disable_collapse?this.schema.options.disable_collapse&&(this.toggle_button.style.display="none"):this.jsoneditor.options.disable_collapse&&(this.toggle_button.style.display="none")),this.add_row_button=this.getButton(this.getItemTitle(),"add","Add "+this.getItemTitle()),this.add_row_button.addEventListener("click",function(b){b.preventDefault(),b.stopPropagation(),a.addRow(),a.refreshValue(),a.refreshRowButtons(),a.onChange(!0)}),a.controls.appendChild(this.add_row_button),this.delete_last_row_button=this.getButton("Last "+this.getItemTitle(),"delete","Delete Last "+this.getItemTitle()),this.delete_last_row_button.addEventListener("click",function(b){b.preventDefault(),b.stopPropagation();var c=a.getValue();c.pop(),a.setValue(c),a.onChange(!0)}),a.controls.appendChild(this.delete_last_row_button),this.remove_all_rows_button=this.getButton("All","delete","Delete All"),this.remove_all_rows_button.addEventListener("click",function(b){b.preventDefault(),b.stopPropagation(),a.setValue([]),a.onChange(!0)}),a.controls.appendChild(this.remove_all_rows_button)}}),f.defaults.editors.multiple=f.AbstractEditor.extend({register:function(){if(this.editors){for(var a=0;a<this.editors.length;a++)this.editors[a]&&this.editors[a].unregister();this.editors[this.type]&&this.editors[this.type].register()}this._super()},unregister:function(){if(this._super(),this.editors)for(var a=0;a<this.editors.length;a++)this.editors[a]&&this.editors[a].unregister()},getNumColumns:function(){return this.editors[this.type]?Math.max(this.editors[this.type].getNumColumns(),4):4},enable:function(){if(this.editors)for(var a=0;a<this.editors.length;a++)this.editors[a]&&this.editors[a].enable();this.switcher.disabled=!1,this._super()},disable:function(){if(this.editors)for(var a=0;a<this.editors.length;a++)this.editors[a]&&this.editors[a].disable();this.switcher.disabled=!0,this._super()},switchEditor:function(a){var b=this;this.editors[a]||this.buildChildEditor(a),b.type=a,b.register();var c=b.getValue();d(b.editors,function(a,d){d&&(b.type===a?(b.keep_values&&d.setValue(c,!0),d.container.style.display=""):d.container.style.display="none")}),b.refreshValue(),b.refreshHeaderText()},buildChildEditor:function(a){var b=this,d=this.types[a],e=b.theme.getChildEditorHolder();b.editor_holder.appendChild(e);var f;"string"==typeof d?(f=c({},b.schema),f.type=d):(f=c({},b.schema,d),f=b.jsoneditor.expandRefs(f),d.required&&Array.isArray(d.required)&&b.schema.required&&Array.isArray(b.schema.required)&&(f.required=b.schema.required.concat(d.required)));var g=b.jsoneditor.getEditorClass(f);b.editors[a]=b.jsoneditor.createEditor(g,{jsoneditor:b.jsoneditor,schema:f,container:e,path:b.path,parent:b,required:!0}),b.editors[a].preBuild(),b.editors[a].build(),b.editors[a].postBuild(),b.editors[a].header&&(b.editors[a].header.style.display="none"),b.editors[a].option=b.switcher_options[a],e.addEventListener("change_header_text",function(){b.refreshHeaderText()}),a!==b.type&&(e.style.display="none")},preBuild:function(){if(this.types=[],this.type=0,this.editors=[],this.validators=[],this.keep_values=!0,"undefined"!=typeof this.jsoneditor.options.keep_oneof_values&&(this.keep_values=this.jsoneditor.options.keep_oneof_values),"undefined"!=typeof this.options.keep_oneof_values&&(this.keep_values=this.options.keep_oneof_values),this.schema.oneOf)this.oneOf=!0,this.types=this.schema.oneOf,d(this.types,function(a,b){}),delete this.schema.oneOf;else{if(this.schema.type&&"any"!==this.schema.type)Array.isArray(this.schema.type)?this.types=this.schema.type:this.types=[this.schema.type];else if(this.types=["string","number","integer","boolean","object","array","null"],this.schema.disallow){var a=this.schema.disallow;"object"==typeof a&&Array.isArray(a)||(a=[a]);var b=[];d(this.types,function(c,d){-1===a.indexOf(d)&&b.push(d)}),this.types=b}delete this.schema.type}this.display_text=this.getDisplayText(this.types)},build:function(){var a=this,b=this.container;this.header=this.label=this.theme.getFormInputLabel(this.getTitle()),this.container.appendChild(this.header),this.switcher=this.theme.getSwitcher(this.display_text),b.appendChild(this.switcher),this.switcher.addEventListener("change",function(b){b.preventDefault(),b.stopPropagation(),a.switchEditor(a.display_text.indexOf(this.value)),a.onChange(!0)}),this.editor_holder=document.createElement("div"),b.appendChild(this.editor_holder),this.switcher_options=this.theme.getSwitcherOptions(this.switcher),d(this.types,function(b,d){a.editors[b]=!1;var e;"string"==typeof d?(e=c({},a.schema),e.type=d):(e=c({},a.schema,d),d.required&&Array.isArray(d.required)&&a.schema.required&&Array.isArray(a.schema.required)&&(e.required=a.schema.required.concat(d.required))),a.validators[b]=new f.Validator(a.jsoneditor,e)}),this.switchEditor(0)},onChildEditorChange:function(a){this.editors[this.type]&&(this.refreshValue(),this.refreshHeaderText()),this._super()},refreshHeaderText:function(){var a=this.getDisplayText(this.types);d(this.switcher_options,function(b,c){c.textContent=a[b]})},refreshValue:function(){this.value=this.editors[this.type].getValue()},setValue:function(a,b){var c=this;d(this.validators,function(b,d){return d.validate(a).length?void 0:(c.type=b,c.switcher.value=c.display_text[b],!1)}),this.switchEditor(this.type),this.editors[this.type].setValue(a,b),this.refreshValue(),c.onChange()},destroy:function(){d(this.editors,function(a,b){b&&b.destroy()}),this.editor_holder&&this.editor_holder.parentNode&&this.editor_holder.parentNode.removeChild(this.editor_holder),this.switcher&&this.switcher.parentNode&&this.switcher.parentNode.removeChild(this.switcher),this._super()},showValidationErrors:function(a){var b=this;this.oneOf?d(this.editors,function(e,f){if(f){var g=b.path+".oneOf["+e+"]",h=[];d(a,function(a,d){if(d.path.substr(0,g.length)===g){var e=c({},d);e.path=b.path+e.path.substr(g.length),h.push(e)}}),f.showValidationErrors(h)}}):d(this.editors,function(b,c){c&&c.showValidationErrors(a)})}}),f.defaults.editors["enum"]=f.AbstractEditor.extend({getNumColumns:function(){return 4},build:function(){this.container;this.title=this.header=this.label=this.theme.getFormInputLabel(this.getTitle()),this.container.appendChild(this.title),this.options.enum_titles=this.options.enum_titles||[],this["enum"]=this.schema["enum"],this.selected=0,this.select_options=[],this.html_values=[];for(var a=this,b=0;b<this["enum"].length;b++)this.select_options[b]=this.options.enum_titles[b]||"Value "+(b+1),this.html_values[b]=this.getHTML(this["enum"][b]);this.switcher=this.theme.getSwitcher(this.select_options),this.container.appendChild(this.switcher),this.display_area=this.theme.getIndentedPanel(),this.container.appendChild(this.display_area),this.options.hide_display&&(this.display_area.style.display="none"),this.switcher.addEventListener("change",function(){a.selected=a.select_options.indexOf(this.value),a.value=a["enum"][a.selected],a.refreshValue(),a.onChange(!0)}),this.value=this["enum"][0],this.refreshValue(),1===this["enum"].length&&(this.switcher.style.display="none")},refreshValue:function(){var a=this;a.selected=-1;var b=JSON.stringify(this.value);return d(this["enum"],function(c,d){return b===JSON.stringify(d)?(a.selected=c,!1):void 0}),a.selected<0?void a.setValue(a["enum"][0]):(this.switcher.value=this.select_options[this.selected],void(this.display_area.innerHTML=this.html_values[this.selected]))},enable:function(){this.always_disabled||(this.switcher.disabled=!1),this._super()},disable:function(){this.switcher.disabled=!0,this._super()},getHTML:function(a){var b=this;if(null===a)return"<em>null</em>";if("object"==typeof a){var c="";return d(a,function(d,e){var f=b.getHTML(e);Array.isArray(a)||(f="<div><em>"+d+"</em>: "+f+"</div>"),c+="<li>"+f+"</li>"}),c=Array.isArray(a)?"<ol>"+c+"</ol>":"<ul style='margin-top:0;margin-bottom:0;padding-top:0;padding-bottom:0;'>"+c+"</ul>"}return"boolean"==typeof a?a?"true":"false":"string"==typeof a?a.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;"):a},setValue:function(a){this.value!==a&&(this.value=a,this.refreshValue(),this.onChange())},destroy:function(){this.display_area&&this.display_area.parentNode&&this.display_area.parentNode.removeChild(this.display_area),this.title&&this.title.parentNode&&this.title.parentNode.removeChild(this.title),this.switcher&&this.switcher.parentNode&&this.switcher.parentNode.removeChild(this.switcher),this._super()}}),f.defaults.editors.select=f.AbstractEditor.extend({setValue:function(a,b){a=this.typecast(a||"");var c=a;this.enum_values.indexOf(c)<0&&(c=this.enum_values[0]),this.value!==c&&(this.input.value=this.enum_options[this.enum_values.indexOf(c)],this.select2&&this.select2.select2("val",this.input.value),this.value=c,this.onChange())},register:function(){this._super(),this.input&&this.input.setAttribute("name",this.formname)},unregister:function(){this._super(),this.input&&this.input.removeAttribute("name")},getNumColumns:function(){if(!this.enum_options)return 3;for(var a=this.getTitle().length,b=0;b<this.enum_options.length;b++)a=Math.max(a,this.enum_options[b].length+4);return Math.min(12,Math.max(a/7,2))},typecast:function(a){return"boolean"===this.schema.type?!!a:"number"===this.schema.type?1*a:"integer"===this.schema.type?Math.floor(1*a):""+a},getValue:function(){return this.value},preBuild:function(){var a=this;if(this.input_type="select",this.enum_options=[],this.enum_values=[],this.enum_display=[],this.schema["enum"]){var b=this.schema.options&&this.schema.options.enum_titles||[];d(this.schema["enum"],function(c,d){a.enum_options[c]=""+d,a.enum_display[c]=""+(b[c]||d),a.enum_values[c]=a.typecast(d)}),this.isRequired()||(a.enum_display.unshift(" "),a.enum_options.unshift("undefined"),a.enum_values.unshift(void 0))}else if("boolean"===this.schema.type)a.enum_display=this.schema.options&&this.schema.options.enum_titles||["true","false"],a.enum_options=["1",""],a.enum_values=[!0,!1],this.isRequired()||(a.enum_display.unshift(" "),a.enum_options.unshift("undefined"),a.enum_values.unshift(void 0));else{if(!this.schema.enumSource)throw"'select' editor requires the enum property to be set.";if(this.enumSource=[],this.enum_display=[],this.enum_options=[],this.enum_values=[],Array.isArray(this.schema.enumSource))for(h=0;h<this.schema.enumSource.length;h++)"string"==typeof this.schema.enumSource[h]?this.enumSource[h]={source:this.schema.enumSource[h]}:Array.isArray(this.schema.enumSource[h])?this.enumSource[h]=this.schema.enumSource[h]:this.enumSource[h]=c({},this.schema.enumSource[h]);else this.schema.enumValue?this.enumSource=[{source:this.schema.enumSource,value:this.schema.enumValue}]:this.enumSource=[{source:this.schema.enumSource}];for(h=0;h<this.enumSource.length;h++)this.enumSource[h].value&&(this.enumSource[h].value=this.jsoneditor.compileTemplate(this.enumSource[h].value,this.template_engine)),this.enumSource[h].title&&(this.enumSource[h].title=this.jsoneditor.compileTemplate(this.enumSource[h].title,this.template_engine)),this.enumSource[h].filter&&(this.enumSource[h].filter=this.jsoneditor.compileTemplate(this.enumSource[h].filter,this.template_engine))}},build:function(){var a=this;this.options.compact||(this.header=this.label=this.theme.getFormInputLabel(this.getTitle())),this.schema.description&&(this.description=this.theme.getFormInputDescription(this.schema.description)),this.options.compact&&(this.container.className+=" compact"),this.input=this.theme.getSelectInput(this.enum_options),this.theme.setSelectOptions(this.input,this.enum_options,this.enum_display),(this.schema.readOnly||this.schema.readonly)&&(this.always_disabled=!0,this.input.disabled=!0),this.input.addEventListener("change",function(b){b.preventDefault(),b.stopPropagation(),a.onInputChange()}),this.control=this.theme.getFormControl(this.label,this.input,this.description),this.container.appendChild(this.control),this.value=this.enum_values[0]},onInputChange:function(){var a=this.input.value,b=a;-1===this.enum_options.indexOf(a)&&(b=this.enum_options[0]),this.value=this.enum_values[this.enum_options.indexOf(a)],this.onChange(!0)},setupSelect2:function(){if(window.jQuery&&window.jQuery.fn&&window.jQuery.fn.select2&&(this.enum_options.length>2||this.enum_options.length&&this.enumSource)){var a=c({},f.plugins.select2);this.schema.options&&this.schema.options.select2_options&&(a=c(a,this.schema.options.select2_options)),this.select2=window.jQuery(this.input).select2(a);var b=this;this.select2.on("select2-blur",function(){b.input.value=b.select2.select2("val"),b.onInputChange()})}else this.select2=null},postBuild:function(){this._super(),this.theme.afterInputReady(this.input),this.setupSelect2()},onWatchedFieldChange:function(){var a,b;if(this.enumSource){a=this.getWatchedFieldValues();for(var c=[],d=[],e=0;e<this.enumSource.length;e++)if(Array.isArray(this.enumSource[e]))c=c.concat(this.enumSource[e]),d=d.concat(this.enumSource[e]);else{var f=[];if(f=Array.isArray(this.enumSource[e].source)?this.enumSource[e].source:a[this.enumSource[e].source]){if(this.enumSource[e].slice&&(f=Array.prototype.slice.apply(f,this.enumSource[e].slice)),this.enumSource[e].filter){var g=[];for(b=0;b<f.length;b++)this.enumSource[e].filter({i:b,item:f[b],watched:a})&&g.push(f[b]);f=g}var h=[],i=[];for(b=0;b<f.length;b++){var j=f[b];this.enumSource[e].value?i[b]=this.enumSource[e].value({i:b,item:j}):i[b]=f[b],this.enumSource[e].title?h[b]=this.enumSource[e].title({i:b,item:j}):h[b]=i[b]}c=c.concat(i),d=d.concat(h)}}var k=this.value;this.theme.setSelectOptions(this.input,c,d),this.enum_options=c,this.enum_display=d,this.enum_values=c,this.select2&&this.select2.select2("destroy"),-1!==c.indexOf(k)?(this.input.value=k,this.value=k):(this.input.value=c[0],this.value=c[0]||"",this.parent?this.parent.onChildEditorChange(this):this.jsoneditor.onChange(),this.jsoneditor.notifyWatchers(this.path)),this.setupSelect2()}this._super()},enable:function(){this.always_disabled||(this.input.disabled=!1,this.select2&&this.select2.select2("enable",!0)),this._super()},disable:function(){this.input.disabled=!0,this.select2&&this.select2.select2("enable",!1),this._super()},destroy:function(){this.label&&this.label.parentNode&&this.label.parentNode.removeChild(this.label),this.description&&this.description.parentNode&&this.description.parentNode.removeChild(this.description),this.input&&this.input.parentNode&&this.input.parentNode.removeChild(this.input),this.select2&&(this.select2.select2("destroy"),this.select2=null),this._super()}}),f.defaults.editors.multiselect=f.AbstractEditor.extend({preBuild:function(){this._super(),this.select_options={},this.select_values={};var a=this.jsoneditor.expandRefs(this.schema.items||{}),b=a["enum"]||[];for(this.option_keys=[],h=0;h<b.length;h++)this.sanitize(b[h])===b[h]&&(this.option_keys.push(b[h]+""),this.select_values[b[h]+""]=b[h])},build:function(){var a,b=this;if(this.options.compact||(this.header=this.label=this.theme.getFormInputLabel(this.getTitle())),this.schema.description&&(this.description=this.theme.getFormInputDescription(this.schema.description)),!this.schema.format&&this.option_keys.length<8||"checkbox"===this.schema.format){for(this.input_type="checkboxes",this.inputs={},this.controls={},a=0;a<this.option_keys.length;a++){this.inputs[this.option_keys[a]]=this.theme.getCheckbox(),this.select_options[this.option_keys[a]]=this.inputs[this.option_keys[a]];var c=this.theme.getCheckboxLabel(this.option_keys[a]);this.controls[this.option_keys[a]]=this.theme.getFormControl(c,this.inputs[this.option_keys[a]])}this.control=this.theme.getMultiCheckboxHolder(this.controls,this.label,this.description)}else{for(this.input_type="select",this.input=this.theme.getSelectInput(this.option_keys),this.input.multiple=!0,this.input.size=Math.min(10,this.option_keys.length),a=0;a<this.option_keys.length;a++)this.select_options[this.option_keys[a]]=this.input.children[a];(this.schema.readOnly||this.schema.readonly)&&(this.always_disabled=!0,this.input.disabled=!0),this.control=this.theme.getFormControl(this.label,this.input,this.description)}this.container.appendChild(this.control),this.control.addEventListener("change",function(c){c.preventDefault(),c.stopPropagation();var d=[];for(a=0;a<b.option_keys.length;a++)(b.select_options[b.option_keys[a]].selected||b.select_options[b.option_keys[a]].checked)&&d.push(b.select_values[b.option_keys[a]]);b.updateValue(d),b.onChange(!0)})},setValue:function(a,b){var c;for(a=a||[],"object"!=typeof a?a=[a]:Array.isArray(a)||(a=[]),c=0;c<a.length;c++)"string"!=typeof a[c]&&(a[c]+="");for(c in this.select_options)this.select_options.hasOwnProperty(c)&&(this.select_options[c]["select"===this.input_type?"selected":"checked"]=-1!==a.indexOf(c));this.updateValue(a),this.onChange()},setupSelect2:function(){if(window.jQuery&&window.jQuery.fn&&window.jQuery.fn.select2){var a=window.jQuery.extend({},f.plugins.select2);this.schema.options&&this.schema.options.select2_options&&(a=c(a,this.schema.options.select2_options)),this.select2=window.jQuery(this.input).select2(a);var b=this;this.select2.on("select2-blur",function(){var a=b.select2.select2("val");b.value=a,b.onChange(!0)})}else this.select2=null},onInputChange:function(){this.value=this.input.value,this.onChange(!0)},postBuild:function(){this._super(),this.setupSelect2()},register:function(){this._super(),this.input&&this.input.setAttribute("name",this.formname)},unregister:function(){this._super(),this.input&&this.input.removeAttribute("name")},getNumColumns:function(){var a=this.getTitle().length;for(var b in this.select_values)this.select_values.hasOwnProperty(b)&&(a=Math.max(a,(this.select_values[b]+"").length+4));return Math.min(12,Math.max(a/7,2))},updateValue:function(a){for(var b=!1,c=[],d=0;d<a.length;d++)if(this.select_options[a[d]+""]){var e=this.sanitize(this.select_values[a[d]]);c.push(e),e!==a[d]&&(b=!0)}else b=!0;return this.value=c,this.select2&&this.select2.select2("val",this.value),b},sanitize:function(a){return"number"===this.schema.items.type?1*a:"integer"===this.schema.items.type?Math.floor(1*a):""+a},enable:function(){if(!this.always_disabled){if(this.input)this.input.disabled=!1;else if(this.inputs)for(var a in this.inputs)this.inputs.hasOwnProperty(a)&&(this.inputs[a].disabled=!1);this.select2&&this.select2.select2("enable",!0)}this._super()},disable:function(){if(this.input)this.input.disabled=!0;else if(this.inputs)for(var a in this.inputs)this.inputs.hasOwnProperty(a)&&(this.inputs[a].disabled=!0);this.select2&&this.select2.select2("enable",!1),this._super()},destroy:function(){this.select2&&(this.select2.select2("destroy"),this.select2=null),this._super()}}),f.defaults.editors.base64=f.AbstractEditor.extend({getNumColumns:function(){return 4},build:function(){var a=this;if(this.title=this.header=this.label=this.theme.getFormInputLabel(this.getTitle()),this.input=this.theme.getFormInputField("hidden"),this.container.appendChild(this.input),!this.schema.readOnly&&!this.schema.readonly){if(!window.FileReader)throw"FileReader required for base64 editor";this.uploader=this.theme.getFormInputField("file"),this.uploader.addEventListener("change",function(b){if(b.preventDefault(),b.stopPropagation(),this.files&&this.files.length){var c=new FileReader;c.onload=function(b){a.value=b.target.result,a.refreshPreview(),a.onChange(!0),c=null},c.readAsDataURL(this.files[0])}})}this.preview=this.theme.getFormInputDescription(this.schema.description),this.container.appendChild(this.preview),this.control=this.theme.getFormControl(this.label,this.uploader||this.input,this.preview),this.container.appendChild(this.control)},refreshPreview:function(){if(this.last_preview!==this.value&&(this.last_preview=this.value,this.preview.innerHTML="",this.value)){var a=this.value.match(/^data:([^;,]+)[;,]/);if(a&&(a=a[1]),a){if(this.preview.innerHTML="<strong>Type:</strong> "+a+", <strong>Size:</strong> "+Math.floor((this.value.length-this.value.split(",")[0].length-1)/1.33333)+" bytes","image"===a.substr(0,5)){this.preview.innerHTML+="<br>";var b=document.createElement("img");b.style.maxWidth="100%",b.style.maxHeight="100px",b.src=this.value,this.preview.appendChild(b)}}else this.preview.innerHTML="<em>Invalid data URI</em>"}},enable:function(){this.uploader&&(this.uploader.disabled=!1),this._super()},disable:function(){this.uploader&&(this.uploader.disabled=!0),this._super()},setValue:function(a){this.value!==a&&(this.value=a,this.input.value=this.value,this.refreshPreview(),this.onChange())},destroy:function(){this.preview&&this.preview.parentNode&&this.preview.parentNode.removeChild(this.preview),this.title&&this.title.parentNode&&this.title.parentNode.removeChild(this.title),this.input&&this.input.parentNode&&this.input.parentNode.removeChild(this.input),this.uploader&&this.uploader.parentNode&&this.uploader.parentNode.removeChild(this.uploader),this._super()}}),f.defaults.editors.upload=f.AbstractEditor.extend({getNumColumns:function(){return 4},build:function(){var a=this;if(this.title=this.header=this.label=this.theme.getFormInputLabel(this.getTitle()),this.input=this.theme.getFormInputField("hidden"),this.container.appendChild(this.input),!this.schema.readOnly&&!this.schema.readonly){if(!this.jsoneditor.options.upload)throw"Upload handler required for upload editor";this.uploader=this.theme.getFormInputField("file"),this.uploader.addEventListener("change",function(b){if(b.preventDefault(),b.stopPropagation(),this.files&&this.files.length){var c=new FileReader;c.onload=function(b){a.preview_value=b.target.result,a.refreshPreview(),a.onChange(!0),c=null},c.readAsDataURL(this.files[0])}})}var b=this.schema.description;b||(b=""),this.preview=this.theme.getFormInputDescription(b),this.container.appendChild(this.preview),this.control=this.theme.getFormControl(this.label,this.uploader||this.input,this.preview),this.container.appendChild(this.control)},refreshPreview:function(){if(this.last_preview!==this.preview_value&&(this.last_preview=this.preview_value,this.preview.innerHTML="",this.preview_value)){var a=this,b=this.preview_value.match(/^data:([^;,]+)[;,]/);b&&(b=b[1]),b||(b="unknown");var c=this.uploader.files[0];if(this.preview.innerHTML="<strong>Type:</strong> "+b+", <strong>Size:</strong> "+c.size+" bytes","image"===b.substr(0,5)){this.preview.innerHTML+="<br>";var d=document.createElement("img");d.style.maxWidth="100%",d.style.maxHeight="100px",d.src=this.preview_value,this.preview.appendChild(d)}this.preview.innerHTML+="<br>";var e=this.getButton("Upload","upload","Upload");this.preview.appendChild(e),
+e.addEventListener("click",function(b){b.preventDefault(),e.setAttribute("disabled","disabled"),a.theme.removeInputError(a.uploader),a.theme.getProgressBar&&(a.progressBar=a.theme.getProgressBar(),a.preview.appendChild(a.progressBar)),a.jsoneditor.options.upload(a.path,c,{success:function(b){a.setValue(b),a.parent?a.parent.onChildEditorChange(a):a.jsoneditor.onChange(),a.progressBar&&a.preview.removeChild(a.progressBar),e.removeAttribute("disabled")},failure:function(b){a.theme.addInputError(a.uploader,b),a.progressBar&&a.preview.removeChild(a.progressBar),e.removeAttribute("disabled")},updateProgress:function(b){a.progressBar&&(b?a.theme.updateProgressBar(a.progressBar,b):a.theme.updateProgressBarUnknown(a.progressBar))}})})}},enable:function(){this.uploader&&(this.uploader.disabled=!1),this._super()},disable:function(){this.uploader&&(this.uploader.disabled=!0),this._super()},setValue:function(a){this.value!==a&&(this.value=a,this.input.value=this.value,this.onChange())},destroy:function(){this.preview&&this.preview.parentNode&&this.preview.parentNode.removeChild(this.preview),this.title&&this.title.parentNode&&this.title.parentNode.removeChild(this.title),this.input&&this.input.parentNode&&this.input.parentNode.removeChild(this.input),this.uploader&&this.uploader.parentNode&&this.uploader.parentNode.removeChild(this.uploader),this._super()}}),f.defaults.editors.checkbox=f.AbstractEditor.extend({setValue:function(a,b){this.value=!!a,this.input.checked=this.value,this.onChange()},register:function(){this._super(),this.input&&this.input.setAttribute("name",this.formname)},unregister:function(){this._super(),this.input&&this.input.removeAttribute("name")},getNumColumns:function(){return Math.min(12,Math.max(this.getTitle().length/7,2))},build:function(){var a=this;this.options.compact||(this.label=this.header=this.theme.getCheckboxLabel(this.getTitle())),this.schema.description&&(this.description=this.theme.getFormInputDescription(this.schema.description)),this.options.compact&&(this.container.className+=" compact"),this.input=this.theme.getCheckbox(),this.control=this.theme.getFormControl(this.label,this.input,this.description),(this.schema.readOnly||this.schema.readonly)&&(this.always_disabled=!0,this.input.disabled=!0),this.input.addEventListener("change",function(b){b.preventDefault(),b.stopPropagation(),a.value=this.checked,a.onChange(!0)}),this.container.appendChild(this.control)},enable:function(){this.always_disabled||(this.input.disabled=!1),this._super()},disable:function(){this.input.disabled=!0,this._super()},destroy:function(){this.label&&this.label.parentNode&&this.label.parentNode.removeChild(this.label),this.description&&this.description.parentNode&&this.description.parentNode.removeChild(this.description),this.input&&this.input.parentNode&&this.input.parentNode.removeChild(this.input),this._super()}});var g=function(){var a=document.documentElement;return a.matches?"matches":a.webkitMatchesSelector?"webkitMatchesSelector":a.mozMatchesSelector?"mozMatchesSelector":a.msMatchesSelector?"msMatchesSelector":a.oMatchesSelector?"oMatchesSelector":void 0}();f.AbstractTheme=a.extend({getContainer:function(){return document.createElement("div")},getFloatRightLinkHolder:function(){var a=document.createElement("div");return a.style=a.style||{},a.style.cssFloat="right",a.style.marginLeft="10px",a},getModal:function(){var a=document.createElement("div");return a.style.backgroundColor="white",a.style.border="1px solid black",a.style.boxShadow="3px 3px black",a.style.position="absolute",a.style.zIndex="10",a.style.display="none",a},getGridContainer:function(){var a=document.createElement("div");return a},getGridRow:function(){var a=document.createElement("div");return a.className="row",a},getGridColumn:function(){var a=document.createElement("div");return a},setGridColumnSize:function(a,b){},getLink:function(a){var b=document.createElement("a");return b.setAttribute("href","#"),b.appendChild(document.createTextNode(a)),b},disableHeader:function(a){a.style.color="#ccc"},disableLabel:function(a){a.style.color="#ccc"},enableHeader:function(a){a.style.color=""},enableLabel:function(a){a.style.color=""},getFormInputLabel:function(a){var b=document.createElement("label");return b.appendChild(document.createTextNode(a)),b},getCheckboxLabel:function(a){var b=this.getFormInputLabel(a);return b.style.fontWeight="normal",b},getHeader:function(a){var b=document.createElement("h3");return"string"==typeof a?b.textContent=a:b.appendChild(a),b},getCheckbox:function(){var a=this.getFormInputField("checkbox");return a.style.display="inline-block",a.style.width="auto",a},getMultiCheckboxHolder:function(a,b,c){var d=document.createElement("div");b&&(b.style.display="block",d.appendChild(b));for(var e in a)a.hasOwnProperty(e)&&(a[e].style.display="inline-block",a[e].style.marginRight="20px",d.appendChild(a[e]));return c&&d.appendChild(c),d},getSelectInput:function(a){var b=document.createElement("select");return a&&this.setSelectOptions(b,a),b},getSwitcher:function(a){var b=this.getSelectInput(a);return b.style.backgroundColor="transparent",b.style.display="inline-block",b.style.fontStyle="italic",b.style.fontWeight="normal",b.style.height="auto",b.style.marginBottom=0,b.style.marginLeft="5px",b.style.padding="0 0 0 3px",b.style.width="auto",b},getSwitcherOptions:function(a){return a.getElementsByTagName("option")},setSwitcherOptions:function(a,b,c){this.setSelectOptions(a,b,c)},setSelectOptions:function(a,b,c){c=c||[],a.innerHTML="";for(var d=0;d<b.length;d++){var e=document.createElement("option");e.setAttribute("value",b[d]),e.textContent=c[d]||b[d],a.appendChild(e)}},getTextareaInput:function(){var a=document.createElement("textarea");return a.style=a.style||{},a.style.width="100%",a.style.height="300px",a.style.boxSizing="border-box",a},getRangeInput:function(a,b,c){var d=this.getFormInputField("range");return d.setAttribute("min",a),d.setAttribute("max",b),d.setAttribute("step",c),d},getFormInputField:function(a){var b=document.createElement("input");return b.setAttribute("type",a),b},afterInputReady:function(a){},getFormControl:function(a,b,c){var d=document.createElement("div");return d.className="form-control",a&&d.appendChild(a),"checkbox"===b.type?a.insertBefore(b,a.firstChild):d.appendChild(b),c&&d.appendChild(c),d},getIndentedPanel:function(){var a=document.createElement("div");return a.style=a.style||{},a.style.paddingLeft="10px",a.style.marginLeft="10px",a.style.borderLeft="1px solid #ccc",a},getChildEditorHolder:function(){return document.createElement("div")},getDescription:function(a){var b=document.createElement("p");return b.innerHTML=a,b},getCheckboxDescription:function(a){return this.getDescription(a)},getFormInputDescription:function(a){return this.getDescription(a)},getHeaderButtonHolder:function(){return this.getButtonHolder()},getButtonHolder:function(){return document.createElement("div")},getButton:function(a,b,c){var d=document.createElement("button");return d.type="button",this.setButtonText(d,a,b,c),d},setButtonText:function(a,b,c,d){a.innerHTML="",c&&(a.appendChild(c),a.innerHTML+=" "),a.appendChild(document.createTextNode(b)),d&&a.setAttribute("title",d)},getTable:function(){return document.createElement("table")},getTableRow:function(){return document.createElement("tr")},getTableHead:function(){return document.createElement("thead")},getTableBody:function(){return document.createElement("tbody")},getTableHeaderCell:function(a){var b=document.createElement("th");return b.textContent=a,b},getTableCell:function(){var a=document.createElement("td");return a},getErrorMessage:function(a){var b=document.createElement("p");return b.style=b.style||{},b.style.color="red",b.appendChild(document.createTextNode(a)),b},addInputError:function(a,b){},removeInputError:function(a){},addTableRowError:function(a){},removeTableRowError:function(a){},getTabHolder:function(){var a=document.createElement("div");return a.innerHTML="<div style='float: left; width: 130px;' class='tabs'></div><div class='content' style='margin-left: 130px;'></div><div style='clear:both;'></div>",a},applyStyles:function(a,b){a.style=a.style||{};for(var c in b)b.hasOwnProperty(c)&&(a.style[c]=b[c])},closest:function(a,b){for(;a&&a!==document;){if(!g)return!1;if(a[g](b))return a;a=a.parentNode}return!1},getTab:function(a){var b=document.createElement("div");return b.appendChild(a),b.style=b.style||{},this.applyStyles(b,{border:"1px solid #ccc",borderWidth:"1px 0 1px 1px",textAlign:"center",lineHeight:"30px",borderRadius:"5px",borderBottomRightRadius:0,borderTopRightRadius:0,fontWeight:"bold",cursor:"pointer"}),b},getTabContentHolder:function(a){return a.children[1]},getTabContent:function(){return this.getIndentedPanel()},markTabActive:function(a){this.applyStyles(a,{opacity:1,background:"white"})},markTabInactive:function(a){this.applyStyles(a,{opacity:.5,background:""})},addTab:function(a,b){a.children[0].appendChild(b)},getBlockLink:function(){var a=document.createElement("a");return a.style.display="block",a},getBlockLinkHolder:function(){var a=document.createElement("div");return a},getLinksHolder:function(){var a=document.createElement("div");return a},createMediaLink:function(a,b,c){a.appendChild(b),c.style.width="100%",a.appendChild(c)},createImageLink:function(a,b,c){a.appendChild(b),b.appendChild(c)}}),f.defaults.themes.bootstrap2=f.AbstractTheme.extend({getRangeInput:function(a,b,c){return this._super(a,b,c)},getGridContainer:function(){var a=document.createElement("div");return a.className="container-fluid",a},getGridRow:function(){var a=document.createElement("div");return a.className="row-fluid",a},getFormInputLabel:function(a){var b=this._super(a);return b.style.display="inline-block",b.style.fontWeight="bold",b},setGridColumnSize:function(a,b){a.className="span"+b},getSelectInput:function(a){var b=this._super(a);return b.style.width="auto",b.style.maxWidth="98%",b},getFormInputField:function(a){var b=this._super(a);return b.style.width="98%",b},afterInputReady:function(a){a.controlgroup||(a.controlgroup=this.closest(a,".control-group"),a.controls=this.closest(a,".controls"),this.closest(a,".compact")&&(a.controlgroup.className=a.controlgroup.className.replace(/control-group/g,"").replace(/[ ]{2,}/g," "),a.controls.className=a.controlgroup.className.replace(/controls/g,"").replace(/[ ]{2,}/g," "),a.style.marginBottom=0))},getIndentedPanel:function(){var a=document.createElement("div");return a.className="well well-small",a},getFormInputDescription:function(a){var b=document.createElement("p");return b.className="help-inline",b.textContent=a,b},getFormControl:function(a,b,c){var d=document.createElement("div");d.className="control-group";var e=document.createElement("div");return e.className="controls",a&&"checkbox"===b.getAttribute("type")?(d.appendChild(e),a.className+=" checkbox",a.appendChild(b),e.appendChild(a),e.style.height="30px"):(a&&(a.className+=" control-label",d.appendChild(a)),e.appendChild(b),d.appendChild(e)),c&&e.appendChild(c),d},getHeaderButtonHolder:function(){var a=this.getButtonHolder();return a.style.marginLeft="10px",a},getButtonHolder:function(){var a=document.createElement("div");return a.className="btn-group",a},getButton:function(a,b,c){var d=this._super(a,b,c);return d.className+=" btn btn-default",d},getTable:function(){var a=document.createElement("table");return a.className="table table-bordered",a.style.width="auto",a.style.maxWidth="none",a},addInputError:function(a,b){a.controlgroup&&a.controls&&(a.controlgroup.className+=" error",a.errmsg?a.errmsg.style.display="":(a.errmsg=document.createElement("p"),a.errmsg.className="help-block errormsg",a.controls.appendChild(a.errmsg)),a.errmsg.textContent=b)},removeInputError:function(a){a.errmsg&&(a.errmsg.style.display="none",a.controlgroup.className=a.controlgroup.className.replace(/\s?error/g,""))},getTabHolder:function(){var a=document.createElement("div");return a.className="tabbable tabs-left",a.innerHTML="<ul class='nav nav-tabs span2' style='margin-right: 0;'></ul><div class='tab-content span10' style='overflow:visible;'></div>",a},getTab:function(a){var b=document.createElement("li"),c=document.createElement("a");return c.setAttribute("href","#"),c.appendChild(a),b.appendChild(c),b},getTabContentHolder:function(a){return a.children[1]},getTabContent:function(){var a=document.createElement("div");return a.className="tab-pane active",a},markTabActive:function(a){a.className+=" active"},markTabInactive:function(a){a.className=a.className.replace(/\s?active/g,"")},addTab:function(a,b){a.children[0].appendChild(b)},getProgressBar:function(){var a=document.createElement("div");a.className="progress";var b=document.createElement("div");return b.className="bar",b.style.width="0%",a.appendChild(b),a},updateProgressBar:function(a,b){a&&(a.firstChild.style.width=b+"%")},updateProgressBarUnknown:function(a){a&&(a.className="progress progress-striped active",a.firstChild.style.width="100%")}}),f.defaults.themes.bootstrap3=f.AbstractTheme.extend({getSelectInput:function(a){var b=this._super(a);return b.className+="form-control",b},setGridColumnSize:function(a,b){a.className="col-md-"+b},afterInputReady:function(a){a.controlgroup||(a.controlgroup=this.closest(a,".form-group"),this.closest(a,".compact")&&(a.controlgroup.style.marginBottom=0))},getTextareaInput:function(){var a=document.createElement("textarea");return a.className="form-control",a},getRangeInput:function(a,b,c){return this._super(a,b,c)},getFormInputField:function(a){var b=this._super(a);return"checkbox"!==a&&(b.className+="form-control"),b},getFormControl:function(a,b,c){var d=document.createElement("div");return a&&"checkbox"===b.type?(d.className+=" checkbox",a.appendChild(b),a.style.fontSize="14px",d.style.marginTop="0",d.appendChild(a),b.style.position="relative",b.style.cssFloat="left"):(d.className+=" form-group",a&&(a.className+=" control-label",d.appendChild(a)),d.appendChild(b)),c&&d.appendChild(c),d},getIndentedPanel:function(){var a=document.createElement("div");return a.className="well well-sm",a},getFormInputDescription:function(a){var b=document.createElement("p");return b.className="help-block",b.innerHTML=a,b},getHeaderButtonHolder:function(){var a=this.getButtonHolder();return a.style.marginLeft="10px",a},getButtonHolder:function(){var a=document.createElement("div");return a.className="btn-group",a},getButton:function(a,b,c){var d=this._super(a,b,c);return d.className+="btn btn-default",d},getTable:function(){var a=document.createElement("table");return a.className="table table-bordered",a.style.width="auto",a.style.maxWidth="none",a},addInputError:function(a,b){a.controlgroup&&(a.controlgroup.className+=" has-error",a.errmsg?a.errmsg.style.display="":(a.errmsg=document.createElement("p"),a.errmsg.className="help-block errormsg",a.controlgroup.appendChild(a.errmsg)),a.errmsg.textContent=b)},removeInputError:function(a){a.errmsg&&(a.errmsg.style.display="none",a.controlgroup.className=a.controlgroup.className.replace(/\s?has-error/g,""))},getTabHolder:function(){var a=document.createElement("div");return a.innerHTML="<div class='tabs list-group col-md-2'></div><div class='col-md-10'></div>",a.className="rows",a},getTab:function(a){var b=document.createElement("a");return b.className="list-group-item",b.setAttribute("href","#"),b.appendChild(a),b},markTabActive:function(a){a.className+=" active"},markTabInactive:function(a){a.className=a.className.replace(/\s?active/g,"")},getProgressBar:function(){var a=0,b=100,c=0,d=document.createElement("div");d.className="progress";var e=document.createElement("div");return e.className="progress-bar",e.setAttribute("role","progressbar"),e.setAttribute("aria-valuenow",c),e.setAttribute("aria-valuemin",a),e.setAttribute("aria-valuenax",b),e.innerHTML=c+"%",d.appendChild(e),d},updateProgressBar:function(a,b){if(a){var c=a.firstChild,d=b+"%";c.setAttribute("aria-valuenow",b),c.style.width=d,c.innerHTML=d}},updateProgressBarUnknown:function(a){if(a){var b=a.firstChild;a.className="progress progress-striped active",b.removeAttribute("aria-valuenow"),b.style.width="100%",b.innerHTML=""}}}),f.defaults.themes.foundation=f.AbstractTheme.extend({getChildEditorHolder:function(){var a=document.createElement("div");return a.style.marginBottom="15px",a},getSelectInput:function(a){var b=this._super(a);return b.style.minWidth="none",b.style.padding="5px",b.style.marginTop="3px",b},getSwitcher:function(a){var b=this._super(a);return b.style.paddingRight="8px",b},afterInputReady:function(a){this.closest(a,".compact")&&(a.style.marginBottom=0),a.group=this.closest(a,".form-control")},getFormInputLabel:function(a){var b=this._super(a);return b.style.display="inline-block",b},getFormInputField:function(a){var b=this._super(a);return b.style.width="100%",b.style.marginBottom="checkbox"===a?"0":"12px",b},getFormInputDescription:function(a){var b=document.createElement("p");return b.textContent=a,b.style.marginTop="-10px",b.style.fontStyle="italic",b},getIndentedPanel:function(){var a=document.createElement("div");return a.className="panel",a},getHeaderButtonHolder:function(){var a=this.getButtonHolder();return a.style.display="inline-block",a.style.marginLeft="10px",a.style.verticalAlign="middle",a},getButtonHolder:function(){var a=document.createElement("div");return a.className="button-group",a},getButton:function(a,b,c){var d=this._super(a,b,c);return d.className+=" small button",d},addInputError:function(a,b){a.group&&(a.group.className+=" error",a.errmsg?a.errmsg.style.display="":(a.insertAdjacentHTML("afterend",'<small class="error"></small>'),a.errmsg=a.parentNode.getElementsByClassName("error")[0]),a.errmsg.textContent=b)},removeInputError:function(a){a.errmsg&&(a.group.className=a.group.className.replace(/ error/g,""),a.errmsg.style.display="none")},getProgressBar:function(){var a=document.createElement("div");a.className="progress";var b=document.createElement("span");return b.className="meter",b.style.width="0%",a.appendChild(b),a},updateProgressBar:function(a,b){a&&(a.firstChild.style.width=b+"%")},updateProgressBarUnknown:function(a){a&&(a.firstChild.style.width="100%")}}),f.defaults.themes.foundation3=f.defaults.themes.foundation.extend({getHeaderButtonHolder:function(){var a=this._super();return a.style.fontSize=".6em",a},getFormInputLabel:function(a){var b=this._super(a);return b.style.fontWeight="bold",b},getTabHolder:function(){var a=document.createElement("div");return a.className="row",a.innerHTML="<dl class='tabs vertical two columns'></dl><div class='tabs-content ten columns'></div>",a},setGridColumnSize:function(a,b){var c=["zero","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve"];a.className="columns "+c[b]},getTab:function(a){var b=document.createElement("dd"),c=document.createElement("a");return c.setAttribute("href","#"),c.appendChild(a),b.appendChild(c),b},getTabContentHolder:function(a){return a.children[1]},getTabContent:function(){var a=document.createElement("div");return a.className="content active",a.style.paddingLeft="5px",a},markTabActive:function(a){a.className+=" active"},markTabInactive:function(a){a.className=a.className.replace(/\s*active/g,"")},addTab:function(a,b){a.children[0].appendChild(b)}}),f.defaults.themes.foundation4=f.defaults.themes.foundation.extend({getHeaderButtonHolder:function(){var a=this._super();return a.style.fontSize=".6em",a},setGridColumnSize:function(a,b){a.className="columns large-"+b},getFormInputDescription:function(a){var b=this._super(a);return b.style.fontSize=".8rem",b},getFormInputLabel:function(a){var b=this._super(a);return b.style.fontWeight="bold",b}}),f.defaults.themes.foundation5=f.defaults.themes.foundation.extend({getFormInputDescription:function(a){var b=this._super(a);return b.style.fontSize=".8rem",b},setGridColumnSize:function(a,b){a.className="columns medium-"+b},getButton:function(a,b,c){var d=this._super(a,b,c);return d.className=d.className.replace(/\s*small/g,"")+" tiny",d},getTabHolder:function(){var a=document.createElement("div");return a.innerHTML="<dl class='tabs vertical'></dl><div class='tabs-content vertical'></div>",a},getTab:function(a){var b=document.createElement("dd"),c=document.createElement("a");return c.setAttribute("href","#"),c.appendChild(a),b.appendChild(c),b},getTabContentHolder:function(a){return a.children[1]},getTabContent:function(){var a=document.createElement("div");return a.className="content active",a.style.paddingLeft="5px",a},markTabActive:function(a){a.className+=" active"},markTabInactive:function(a){a.className=a.className.replace(/\s*active/g,"")},addTab:function(a,b){a.children[0].appendChild(b)}}),f.defaults.themes.html=f.AbstractTheme.extend({getFormInputLabel:function(a){var b=this._super(a);return b.style.display="block",b.style.marginBottom="3px",b.style.fontWeight="bold",b},getFormInputDescription:function(a){var b=this._super(a);return b.style.fontSize=".8em",b.style.margin=0,b.style.display="inline-block",b.style.fontStyle="italic",b},getIndentedPanel:function(){var a=this._super();return a.style.border="1px solid #ddd",a.style.padding="5px",a.style.margin="5px",a.style.borderRadius="3px",a},getChildEditorHolder:function(){var a=this._super();return a.style.marginBottom="8px",a},getHeaderButtonHolder:function(){var a=this.getButtonHolder();return a.style.display="inline-block",a.style.marginLeft="10px",a.style.fontSize=".8em",a.style.verticalAlign="middle",a},getTable:function(){var a=this._super();return a.style.borderBottom="1px solid #ccc",a.style.marginBottom="5px",a},addInputError:function(a,b){if(a.style.borderColor="red",a.errmsg)a.errmsg.style.display="block";else{var c=this.closest(a,".form-control");a.errmsg=document.createElement("div"),a.errmsg.setAttribute("class","errmsg"),a.errmsg.style=a.errmsg.style||{},a.errmsg.style.color="red",c.appendChild(a.errmsg)}a.errmsg.innerHTML="",a.errmsg.appendChild(document.createTextNode(b))},removeInputError:function(a){a.style.borderColor="",a.errmsg&&(a.errmsg.style.display="none")},getProgressBar:function(){var a=100,b=0,c=document.createElement("progress");return c.setAttribute("max",a),c.setAttribute("value",b),c},updateProgressBar:function(a,b){a&&a.setAttribute("value",b)},updateProgressBarUnknown:function(a){a&&a.removeAttribute("value")}}),f.defaults.themes.jqueryui=f.AbstractTheme.extend({getTable:function(){var a=this._super();return a.setAttribute("cellpadding",5),a.setAttribute("cellspacing",0),a},getTableHeaderCell:function(a){var b=this._super(a);return b.className="ui-state-active",b.style.fontWeight="bold",b},getTableCell:function(){var a=this._super();return a.className="ui-widget-content",a},getHeaderButtonHolder:function(){var a=this.getButtonHolder();return a.style.marginLeft="10px",a.style.fontSize=".6em",a.style.display="inline-block",a},getFormInputDescription:function(a){var b=this.getDescription(a);return b.style.marginLeft="10px",b.style.display="inline-block",b},getFormControl:function(a,b,c){var d=this._super(a,b,c);return"checkbox"===b.type?(d.style.lineHeight="25px",d.style.padding="3px 0"):d.style.padding="4px 0 8px 0",d},getDescription:function(a){var b=document.createElement("span");return b.style.fontSize=".8em",b.style.fontStyle="italic",b.textContent=a,b},getButtonHolder:function(){var a=document.createElement("div");return a.className="ui-buttonset",a.style.fontSize=".7em",a},getFormInputLabel:function(a){var b=document.createElement("label");return b.style.fontWeight="bold",b.style.display="block",b.textContent=a,b},getButton:function(a,b,c){var d=document.createElement("button");d.className="ui-button ui-widget ui-state-default ui-corner-all",b&&!a?(d.className+=" ui-button-icon-only",b.className+=" ui-button-icon-primary ui-icon-primary",d.appendChild(b)):b?(d.className+=" ui-button-text-icon-primary",b.className+=" ui-button-icon-primary ui-icon-primary",d.appendChild(b)):d.className+=" ui-button-text-only";var e=document.createElement("span");return e.className="ui-button-text",e.textContent=a||c||".",d.appendChild(e),d.setAttribute("title",c),d},setButtonText:function(a,b,c,d){a.innerHTML="",a.className="ui-button ui-widget ui-state-default ui-corner-all",c&&!b?(a.className+=" ui-button-icon-only",c.className+=" ui-button-icon-primary ui-icon-primary",a.appendChild(c)):c?(a.className+=" ui-button-text-icon-primary",c.className+=" ui-button-icon-primary ui-icon-primary",a.appendChild(c)):a.className+=" ui-button-text-only";var e=document.createElement("span");e.className="ui-button-text",e.textContent=b||d||".",a.appendChild(e),a.setAttribute("title",d)},getIndentedPanel:function(){var a=document.createElement("div");return a.className="ui-widget-content ui-corner-all",a.style.padding="1em 1.4em",a.style.marginBottom="20px",a},afterInputReady:function(a){a.controls||(a.controls=this.closest(a,".form-control"))},addInputError:function(a,b){a.controls&&(a.errmsg?a.errmsg.style.display="":(a.errmsg=document.createElement("div"),a.errmsg.className="ui-state-error",a.controls.appendChild(a.errmsg)),a.errmsg.textContent=b)},removeInputError:function(a){a.errmsg&&(a.errmsg.style.display="none")},markTabActive:function(a){a.className=a.className.replace(/\s*ui-widget-header/g,"")+" ui-state-active"},markTabInactive:function(a){a.className=a.className.replace(/\s*ui-state-active/g,"")+" ui-widget-header"}}),f.AbstractIconLib=a.extend({mapping:{collapse:"",expand:"","delete":"",edit:"",add:"",cancel:"",save:"",moveup:"",movedown:""},icon_prefix:"",getIconClass:function(a){return this.mapping[a]?this.icon_prefix+this.mapping[a]:null},getIcon:function(a){var b=this.getIconClass(a);if(!b)return null;var c=document.createElement("i");return c.className=b,c}}),f.defaults.iconlibs.bootstrap2=f.AbstractIconLib.extend({mapping:{collapse:"chevron-down",expand:"chevron-up","delete":"trash",edit:"pencil",add:"plus",cancel:"ban-circle",save:"ok",moveup:"arrow-up",movedown:"arrow-down"},icon_prefix:"icon-"}),f.defaults.iconlibs.bootstrap3=f.AbstractIconLib.extend({mapping:{collapse:"chevron-down",expand:"chevron-right","delete":"remove",edit:"pencil",add:"plus",cancel:"floppy-remove",save:"floppy-saved",moveup:"arrow-up",movedown:"arrow-down"},icon_prefix:"glyphicon glyphicon-"}),f.defaults.iconlibs.fontawesome3=f.AbstractIconLib.extend({mapping:{collapse:"chevron-down",expand:"chevron-right","delete":"remove",edit:"pencil",add:"plus",cancel:"ban-circle",save:"save",moveup:"arrow-up",movedown:"arrow-down"},icon_prefix:"icon-"}),f.defaults.iconlibs.fontawesome4=f.AbstractIconLib.extend({mapping:{collapse:"caret-square-o-down",expand:"caret-square-o-right","delete":"times",edit:"pencil",add:"plus",cancel:"ban",save:"save",moveup:"arrow-up",movedown:"arrow-down"},icon_prefix:"fa fa-"}),f.defaults.iconlibs.foundation2=f.AbstractIconLib.extend({mapping:{collapse:"minus",expand:"plus","delete":"remove",edit:"edit",add:"add-doc",cancel:"error",save:"checkmark",moveup:"up-arrow",movedown:"down-arrow"},icon_prefix:"foundicon-"}),f.defaults.iconlibs.foundation3=f.AbstractIconLib.extend({mapping:{collapse:"minus",expand:"plus","delete":"x",edit:"pencil",add:"page-add",cancel:"x-circle",save:"save",moveup:"arrow-up",movedown:"arrow-down"},icon_prefix:"fi-"}),f.defaults.iconlibs.jqueryui=f.AbstractIconLib.extend({mapping:{collapse:"triangle-1-s",expand:"triangle-1-e","delete":"trash",edit:"pencil",add:"plusthick",cancel:"closethick",save:"disk",moveup:"arrowthick-1-n",movedown:"arrowthick-1-s"},icon_prefix:"ui-icon ui-icon-"}),f.defaults.templates["default"]=function(){return{compile:function(a){var b=a.match(/{{\s*([a-zA-Z0-9\-_ \.]+)\s*}}/g),c=b&&b.length;if(!c)return function(){return a};for(var d=[],e=function(a){var c,e=b[a].replace(/[{}]+/g,"").trim().split("."),f=e.length;if(f>1){var g;c=function(b){for(g=b,a=0;f>a&&(g=g[e[a]],g);a++);return g}}else e=e[0],c=function(a){return a[e]};d.push({s:b[a],r:c})},f=0;c>f;f++)e(f);return function(b){var e,g=a+"";for(f=0;c>f;f++)e=d[f],g=g.replace(e.s,e.r(b));return g}}}},f.defaults.templates.ejs=function(){return window.EJS?{compile:function(a){var b=new window.EJS({text:a});return function(a){return b.render(a)}}}:!1},f.defaults.templates.handlebars=function(){return window.Handlebars},f.defaults.templates.hogan=function(){return window.Hogan?{compile:function(a){var b=window.Hogan.compile(a);return function(a){return b.render(a)}}}:!1},f.defaults.templates.markup=function(){return window.Mark&&window.Mark.up?{compile:function(a){return function(b){return window.Mark.up(a,b)}}}:!1},f.defaults.templates.mustache=function(){return window.Mustache?{compile:function(a){return function(b){return window.Mustache.render(a,b)}}}:!1},f.defaults.templates.swig=function(){return window.swig},f.defaults.templates.underscore=function(){return window._?{compile:function(a){return function(b){return window._.template(a,b)}}}:!1},f.defaults.theme="html",f.defaults.template="default",f.defaults.options={},f.defaults.translate=function(a,b){var c=f.defaults.languages[f.defaults.language];if(!c)throw"Unknown language "+f.defaults.language;var d=c[a]||f.defaults.languages[f.defaults.default_language][a];if("undefined"==typeof d)throw"Unknown translate string "+a;if(b)for(var e=0;e<b.length;e++)d=d.replace(new RegExp("\\{\\{"+e+"}}","g"),b[e]);return d},f.defaults.default_language="en",f.defaults.language=f.defaults.default_language,f.defaults.languages.en={error_notset:"Property must be set",error_notempty:"Value required",error_enum:"Value must be one of the enumerated values",error_anyOf:"Value must validate against at least one of the provided schemas",error_oneOf:"Value must validate against exactly one of the provided schemas. It currently validates against {{0}} of the schemas.",error_not:"Value must not validate against the provided schema",error_type_union:"Value must be one of the provided types",error_type:"Value must be of type {{0}}",error_disallow_union:"Value must not be one of the provided disallowed types",error_disallow:"Value must not be of type {{0}}",error_multipleOf:"Value must be a multiple of {{0}}",error_maximum_excl:"Value must be less than {{0}}",error_maximum_incl:"Value must at most {{0}}",error_minimum_excl:"Value must be greater than {{0}}",error_minimum_incl:"Value must be at least {{0}}",error_maxLength:"Value must be at most {{0}} characters long",error_minLength:"Value must be at least {{0}} characters long",error_pattern:"Value must match the provided pattern",error_additionalItems:"No additional items allowed in this array",error_maxItems:"Value must have at most {{0}} items",error_minItems:"Value must have at least {{0}} items",error_uniqueItems:"Array must have unique items",error_maxProperties:"Object must have at most {{0}} properties",error_minProperties:"Object must have at least {{0}} properties",error_required:"Object is missing the required property '{{0}}'",error_additional_properties:"No additional properties allowed, but property {{0}} is set",error_dependency:"Must have property {{0}}"},f.plugins={ace:{theme:""},epiceditor:{},sceditor:{},select2:{}};for(var h in f.defaults.editors)f.defaults.editors.hasOwnProperty(h)&&(f.defaults.editors[h].options=f.defaults.editors.options||{});f.defaults.resolvers.unshift(function(a){return"string"!=typeof a.type?"multiple":void 0}),f.defaults.resolvers.unshift(function(a){return"string"==typeof a.type?a.type:void 0}),f.defaults.resolvers.unshift(function(a){return"boolean"===a.type?"checkbox"===a.format||a.options&&a.options.checkbox?"checkbox":"select":void 0}),f.defaults.resolvers.unshift(function(a){return"any"===a.type?"multiple":void 0}),f.defaults.resolvers.unshift(function(a){return"string"===a.type&&a.media&&"base64"===a.media.binaryEncoding?"base64":void 0}),f.defaults.resolvers.unshift(function(a){return"string"===a.type&&"url"===a.format&&a.options&&a.options.upload===!0&&window.FileReader?"upload":void 0}),f.defaults.resolvers.unshift(function(a){return"array"==a.type&&"table"==a.format?"table":void 0;
+}),f.defaults.resolvers.unshift(function(a){return a.enumSource?"select":void 0}),f.defaults.resolvers.unshift(function(a){if(a["enum"]){if("array"===a.type||"object"===a.type)return"enum";if("number"===a.type||"integer"===a.type||"string"===a.type)return"select"}}),f.defaults.resolvers.unshift(function(a){return"array"===a.type&&a.items&&!Array.isArray(a.items)&&a.uniqueItems&&a.items["enum"]&&["string","number","integer"].indexOf(a.items.type)>=0?"multiselect":void 0}),f.defaults.resolvers.unshift(function(a){return a.oneOf?"multiple":void 0}),function(){if(window.jQuery||window.Zepto){var a=window.jQuery||window.Zepto;a.jsoneditor=f.defaults,a.fn.jsoneditor=function(a){var b=this,c=this.data("jsoneditor");if("value"===a){if(!c)throw"Must initialize jsoneditor before getting/setting the value";if(!(arguments.length>1))return c.getValue();c.setValue(arguments[1])}else{if("validate"===a){if(!c)throw"Must initialize jsoneditor before validating";return arguments.length>1?c.validate(arguments[1]):c.validate()}"destroy"===a?c&&(c.destroy(),this.data("jsoneditor",null)):(c&&c.destroy(),c=new f(this.get(0),a),this.data("jsoneditor",c),c.on("change",function(){b.trigger("change")}),c.on("ready",function(){b.trigger("ready")}))}return this}}}(),window.JSONEditor=f}();
\ No newline at end of file
diff --git a/htdocs/Libs/jsTree/jstree.js b/htdocs/Libs/jsTree/jstree.js
new file mode 100644
index 0000000..c749f37
--- /dev/null
+++ b/htdocs/Libs/jsTree/jstree.js
@@ -0,0 +1,7239 @@
+/*globals jQuery, define, exports, require, window, document, postMessage */
+(function (factory) {
+	"use strict";
+	if (typeof define === 'function' && define.amd) {
+		define(['jquery'], factory);
+	}
+	else if(typeof exports === 'object') {
+		factory(require('jquery'));
+	}
+	else {
+		factory(jQuery);
+	}
+}(function ($, undefined) {
+	"use strict";
+/*!
+ * jsTree 3.0.9
+ * http://jstree.com/
+ *
+ * Copyright (c) 2014 Ivan Bozhanov (http://vakata.com)
+ *
+ * Licensed same as jquery - under the terms of the MIT License
+ *   http://www.opensource.org/licenses/mit-license.php
+ */
+/*!
+ * if using jslint please allow for the jQuery global and use following options: 
+ * jslint: browser: true, ass: true, bitwise: true, continue: true, nomen: true, plusplus: true, regexp: true, unparam: true, todo: true, white: true
+ */
+
+	// prevent another load? maybe there is a better way?
+	if($.jstree) {
+		return;
+	}
+
+	/**
+	 * ### jsTree core functionality
+	 */
+
+	// internal variables
+	var instance_counter = 0,
+		ccp_node = false,
+		ccp_mode = false,
+		ccp_inst = false,
+		themes_loaded = [],
+		src = $('script:last').attr('src'),
+		_d = document, _node = _d.createElement('LI'), _temp1, _temp2;
+
+	_node.setAttribute('role', 'treeitem');
+	_temp1 = _d.createElement('I');
+	_temp1.className = 'jstree-icon jstree-ocl';
+	_temp1.setAttribute('role', 'presentation');
+	_node.appendChild(_temp1);
+	_temp1 = _d.createElement('A');
+	_temp1.className = 'jstree-anchor';
+	_temp1.setAttribute('href','#');
+	_temp1.setAttribute('tabindex','-1');
+	_temp2 = _d.createElement('I');
+	_temp2.className = 'jstree-icon jstree-themeicon';
+	_temp2.setAttribute('role', 'presentation');
+	_temp1.appendChild(_temp2);
+	_node.appendChild(_temp1);
+	_temp1 = _temp2 = null;
+
+
+	/**
+	 * holds all jstree related functions and variables, including the actual class and methods to create, access and manipulate instances.
+	 * @name $.jstree
+	 */
+	$.jstree = {
+		/** 
+		 * specifies the jstree version in use
+		 * @name $.jstree.version
+		 */
+		version : '3.0.9',
+		/**
+		 * holds all the default options used when creating new instances
+		 * @name $.jstree.defaults
+		 */
+		defaults : {
+			/**
+			 * configure which plugins will be active on an instance. Should be an array of strings, where each element is a plugin name. The default is `[]`
+			 * @name $.jstree.defaults.plugins
+			 */
+			plugins : []
+		},
+		/**
+		 * stores all loaded jstree plugins (used internally)
+		 * @name $.jstree.plugins
+		 */
+		plugins : {},
+		path : src && src.indexOf('/') !== -1 ? src.replace(/\/[^\/]+$/,'') : '',
+		idregex : /[\\:&!^|()\[\]<>@*'+~#";.,=\- \/${}%?`]/g
+	};
+	/**
+	 * creates a jstree instance
+	 * @name $.jstree.create(el [, options])
+	 * @param {DOMElement|jQuery|String} el the element to create the instance on, can be jQuery extended or a selector
+	 * @param {Object} options options for this instance (extends `$.jstree.defaults`)
+	 * @return {jsTree} the new instance
+	 */
+	$.jstree.create = function (el, options) {
+		var tmp = new $.jstree.core(++instance_counter),
+			opt = options;
+		options = $.extend(true, {}, $.jstree.defaults, options);
+		if(opt && opt.plugins) {
+			options.plugins = opt.plugins;
+		}
+		$.each(options.plugins, function (i, k) {
+			if(i !== 'core') {
+				tmp = tmp.plugin(k, options[k]);
+			}
+		});
+		tmp.init(el, options);
+		return tmp;
+	};
+	/**
+	 * remove all traces of jstree from the DOM and destroy all instances
+	 * @name $.jstree.destroy()
+	 */
+	$.jstree.destroy = function () {
+		$('.jstree:jstree').jstree('destroy');
+		$(document).off('.jstree');
+	};
+	/**
+	 * the jstree class constructor, used only internally
+	 * @private
+	 * @name $.jstree.core(id)
+	 * @param {Number} id this instance's index
+	 */
+	$.jstree.core = function (id) {
+		this._id = id;
+		this._cnt = 0;
+		this._wrk = null;
+		this._data = {
+			core : {
+				themes : {
+					name : false,
+					dots : false,
+					icons : false
+				},
+				selected : [],
+				last_error : {},
+				working : false,
+				worker_queue : [],
+				focused : null
+			}
+		};
+	};
+	/**
+	 * get a reference to an existing instance
+	 *
+	 * __Examples__
+	 *
+	 *	// provided a container with an ID of "tree", and a nested node with an ID of "branch"
+	 *	// all of there will return the same instance
+	 *	$.jstree.reference('tree');
+	 *	$.jstree.reference('#tree');
+	 *	$.jstree.reference($('#tree'));
+	 *	$.jstree.reference(document.getElementByID('tree'));
+	 *	$.jstree.reference('branch');
+	 *	$.jstree.reference('#branch');
+	 *	$.jstree.reference($('#branch'));
+	 *	$.jstree.reference(document.getElementByID('branch'));
+	 *
+	 * @name $.jstree.reference(needle)
+	 * @param {DOMElement|jQuery|String} needle
+	 * @return {jsTree|null} the instance or `null` if not found
+	 */
+	$.jstree.reference = function (needle) {
+		var tmp = null,
+			obj = null;
+		if(needle && needle.id) { needle = needle.id; }
+
+		if(!obj || !obj.length) {
+			try { obj = $(needle); } catch (ignore) { }
+		}
+		if(!obj || !obj.length) {
+			try { obj = $('#' + needle.replace($.jstree.idregex,'\\$&')); } catch (ignore) { }
+		}
+		if(obj && obj.length && (obj = obj.closest('.jstree')).length && (obj = obj.data('jstree'))) {
+			tmp = obj;
+		}
+		else {
+			$('.jstree').each(function () {
+				var inst = $(this).data('jstree');
+				if(inst && inst._model.data[needle]) {
+					tmp = inst;
+					return false;
+				}
+			});
+		}
+		return tmp;
+	};
+	/**
+	 * Create an instance, get an instance or invoke a command on a instance. 
+	 * 
+	 * If there is no instance associated with the current node a new one is created and `arg` is used to extend `$.jstree.defaults` for this new instance. There would be no return value (chaining is not broken).
+	 * 
+	 * If there is an existing instance and `arg` is a string the command specified by `arg` is executed on the instance, with any additional arguments passed to the function. If the function returns a value it will be returned (chaining could break depending on function).
+	 * 
+	 * If there is an existing instance and `arg` is not a string the instance itself is returned (similar to `$.jstree.reference`).
+	 * 
+	 * In any other case - nothing is returned and chaining is not broken.
+	 *
+	 * __Examples__
+	 *
+	 *	$('#tree1').jstree(); // creates an instance
+	 *	$('#tree2').jstree({ plugins : [] }); // create an instance with some options
+	 *	$('#tree1').jstree('open_node', '#branch_1'); // call a method on an existing instance, passing additional arguments
+	 *	$('#tree2').jstree(); // get an existing instance (or create an instance)
+	 *	$('#tree2').jstree(true); // get an existing instance (will not create new instance)
+	 *	$('#branch_1').jstree().select_node('#branch_1'); // get an instance (using a nested element and call a method)
+	 *
+	 * @name $().jstree([arg])
+	 * @param {String|Object} arg
+	 * @return {Mixed}
+	 */
+	$.fn.jstree = function (arg) {
+		// check for string argument
+		var is_method	= (typeof arg === 'string'),
+			args		= Array.prototype.slice.call(arguments, 1),
+			result		= null;
+		if(arg === true && !this.length) { return false; }
+		this.each(function () {
+			// get the instance (if there is one) and method (if it exists)
+			var instance = $.jstree.reference(this),
+				method = is_method && instance ? instance[arg] : null;
+			// if calling a method, and method is available - execute on the instance
+			result = is_method && method ?
+				method.apply(instance, args) :
+				null;
+			// if there is no instance and no method is being called - create one
+			if(!instance && !is_method && (arg === undefined || $.isPlainObject(arg))) {
+				$(this).data('jstree', new $.jstree.create(this, arg));
+			}
+			// if there is an instance and no method is called - return the instance
+			if( (instance && !is_method) || arg === true ) {
+				result = instance || false;
+			}
+			// if there was a method call which returned a result - break and return the value
+			if(result !== null && result !== undefined) {
+				return false;
+			}
+		});
+		// if there was a method call with a valid return value - return that, otherwise continue the chain
+		return result !== null && result !== undefined ?
+			result : this;
+	};
+	/**
+	 * used to find elements containing an instance
+	 *
+	 * __Examples__
+	 *
+	 *	$('div:jstree').each(function () {
+	 *		$(this).jstree('destroy');
+	 *	});
+	 *
+	 * @name $(':jstree')
+	 * @return {jQuery}
+	 */
+	$.expr[':'].jstree = $.expr.createPseudo(function(search) {
+		return function(a) {
+			return $(a).hasClass('jstree') &&
+				$(a).data('jstree') !== undefined;
+		};
+	});
+
+	/**
+	 * stores all defaults for the core
+	 * @name $.jstree.defaults.core
+	 */
+	$.jstree.defaults.core = {
+		/**
+		 * data configuration
+		 * 
+		 * If left as `false` the HTML inside the jstree container element is used to populate the tree (that should be an unordered list with list items).
+		 *
+		 * You can also pass in a HTML string or a JSON array here.
+		 * 
+		 * It is possible to pass in a standard jQuery-like AJAX config and jstree will automatically determine if the response is JSON or HTML and use that to populate the tree. 
+		 * In addition to the standard jQuery ajax options here you can suppy functions for `data` and `url`, the functions will be run in the current instance's scope and a param will be passed indicating which node is being loaded, the return value of those functions will be used.
+		 * 
+		 * The last option is to specify a function, that function will receive the node being loaded as argument and a second param which is a function which should be called with the result.
+		 *
+		 * __Examples__
+		 *
+		 *	// AJAX
+		 *	$('#tree').jstree({
+		 *		'core' : {
+		 *			'data' : {
+		 *				'url' : '/get/children/',
+		 *				'data' : function (node) {
+		 *					return { 'id' : node.id };
+		 *				}
+		 *			}
+		 *		});
+		 *
+		 *	// direct data
+		 *	$('#tree').jstree({
+		 *		'core' : {
+		 *			'data' : [
+		 *				'Simple root node',
+		 *				{
+		 *					'id' : 'node_2',
+		 *					'text' : 'Root node with options',
+		 *					'state' : { 'opened' : true, 'selected' : true },
+		 *					'children' : [ { 'text' : 'Child 1' }, 'Child 2']
+		 *				}
+		 *			]
+		 *		});
+		 *	
+		 *	// function
+		 *	$('#tree').jstree({
+		 *		'core' : {
+		 *			'data' : function (obj, callback) {
+		 *				callback.call(this, ['Root 1', 'Root 2']);
+		 *			}
+		 *		});
+		 * 
+		 * @name $.jstree.defaults.core.data
+		 */
+		data			: false,
+		/**
+		 * configure the various strings used throughout the tree
+		 *
+		 * You can use an object where the key is the string you need to replace and the value is your replacement.
+		 * Another option is to specify a function which will be called with an argument of the needed string and should return the replacement.
+		 * If left as `false` no replacement is made.
+		 *
+		 * __Examples__
+		 *
+		 *	$('#tree').jstree({
+		 *		'core' : {
+		 *			'strings' : {
+		 *				'Loading ...' : 'Please wait ...'
+		 *			}
+		 *		}
+		 *	});
+		 *
+		 * @name $.jstree.defaults.core.strings
+		 */
+		strings			: false,
+		/**
+		 * determines what happens when a user tries to modify the structure of the tree
+		 * If left as `false` all operations like create, rename, delete, move or copy are prevented.
+		 * You can set this to `true` to allow all interactions or use a function to have better control.
+		 *
+		 * __Examples__
+		 *
+		 *	$('#tree').jstree({
+		 *		'core' : {
+		 *			'check_callback' : function (operation, node, node_parent, node_position, more) {
+		 *				// operation can be 'create_node', 'rename_node', 'delete_node', 'move_node' or 'copy_node'
+		 *				// in case of 'rename_node' node_position is filled with the new node name
+		 *				return operation === 'rename_node' ? true : false;
+		 *			}
+		 *		}
+		 *	});
+		 * 
+		 * @name $.jstree.defaults.core.check_callback
+		 */
+		check_callback	: false,
+		/**
+		 * a callback called with a single object parameter in the instance's scope when something goes wrong (operation prevented, ajax failed, etc)
+		 * @name $.jstree.defaults.core.error
+		 */
+		error			: $.noop,
+		/**
+		 * the open / close animation duration in milliseconds - set this to `false` to disable the animation (default is `200`)
+		 * @name $.jstree.defaults.core.animation
+		 */
+		animation		: 200,
+		/**
+		 * a boolean indicating if multiple nodes can be selected
+		 * @name $.jstree.defaults.core.multiple
+		 */
+		multiple		: true,
+		/**
+		 * theme configuration object
+		 * @name $.jstree.defaults.core.themes
+		 */
+		themes			: {
+			/**
+			 * the name of the theme to use (if left as `false` the default theme is used)
+			 * @name $.jstree.defaults.core.themes.name
+			 */
+			name			: false,
+			/**
+			 * the URL of the theme's CSS file, leave this as `false` if you have manually included the theme CSS (recommended). You can set this to `true` too which will try to autoload the theme.
+			 * @name $.jstree.defaults.core.themes.url
+			 */
+			url				: false,
+			/**
+			 * the location of all jstree themes - only used if `url` is set to `true`
+			 * @name $.jstree.defaults.core.themes.dir
+			 */
+			dir				: false,
+			/**
+			 * a boolean indicating if connecting dots are shown
+			 * @name $.jstree.defaults.core.themes.dots
+			 */
+			dots			: true,
+			/**
+			 * a boolean indicating if node icons are shown
+			 * @name $.jstree.defaults.core.themes.icons
+			 */
+			icons			: true,
+			/**
+			 * a boolean indicating if the tree background is striped
+			 * @name $.jstree.defaults.core.themes.stripes
+			 */
+			stripes			: false,
+			/**
+			 * a string (or boolean `false`) specifying the theme variant to use (if the theme supports variants)
+			 * @name $.jstree.defaults.core.themes.variant
+			 */
+			variant			: false,
+			/**
+			 * a boolean specifying if a reponsive version of the theme should kick in on smaller screens (if the theme supports it). Defaults to `false`.
+			 * @name $.jstree.defaults.core.themes.responsive
+			 */
+			responsive		: false
+		},
+		/**
+		 * if left as `true` all parents of all selected nodes will be opened once the tree loads (so that all selected nodes are visible to the user)
+		 * @name $.jstree.defaults.core.expand_selected_onload
+		 */
+		expand_selected_onload : true,
+		/**
+		 * if left as `true` web workers will be used to parse incoming JSON data where possible, so that the UI will not be blocked by large requests. Workers are however about 30% slower. Defaults to `true`
+		 * @name $.jstree.defaults.core.worker
+		 */
+		worker : true,
+		/**
+		 * Force node text to plain text (and escape HTML). Defaults to `false`
+		 * @name $.jstree.defaults.core.force_text
+		 */
+		force_text : false,
+		/**
+		 * Should the node should be toggled if the text is double clicked . Defaults to `true`
+		 * @name $.jstree.defaults.core.dblclick_toggle
+		 */
+		dblclick_toggle : true
+	};
+	$.jstree.core.prototype = {
+		/**
+		 * used to decorate an instance with a plugin. Used internally.
+		 * @private
+		 * @name plugin(deco [, opts])
+		 * @param  {String} deco the plugin to decorate with
+		 * @param  {Object} opts options for the plugin
+		 * @return {jsTree}
+		 */
+		plugin : function (deco, opts) {
+			var Child = $.jstree.plugins[deco];
+			if(Child) {
+				this._data[deco] = {};
+				Child.prototype = this;
+				return new Child(opts, this);
+			}
+			return this;
+		},
+		/**
+		 * used to decorate an instance with a plugin. Used internally.
+		 * @private
+		 * @name init(el, optons)
+		 * @param {DOMElement|jQuery|String} el the element we are transforming
+		 * @param {Object} options options for this instance
+		 * @trigger init.jstree, loading.jstree, loaded.jstree, ready.jstree, changed.jstree
+		 */
+		init : function (el, options) {
+			this._model = {
+				data : {
+					'#' : {
+						id : '#',
+						parent : null,
+						parents : [],
+						children : [],
+						children_d : [],
+						state : { loaded : false }
+					}
+				},
+				changed : [],
+				force_full_redraw : false,
+				redraw_timeout : false,
+				default_state : {
+					loaded : true,
+					opened : false,
+					selected : false,
+					disabled : false
+				}
+			};
+
+			this.element = $(el).addClass('jstree jstree-' + this._id);
+			this.settings = options;
+
+			this._data.core.ready = false;
+			this._data.core.loaded = false;
+			this._data.core.rtl = (this.element.css("direction") === "rtl");
+			this.element[this._data.core.rtl ? 'addClass' : 'removeClass']("jstree-rtl");
+			this.element.attr('role','tree');
+			if(this.settings.core.multiple) {
+				this.element.attr('aria-multiselectable', true);
+			}
+			if(!this.element.attr('tabindex')) {
+				this.element.attr('tabindex','0');
+			}
+
+			this.bind();
+			/**
+			 * triggered after all events are bound
+			 * @event
+			 * @name init.jstree
+			 */
+			this.trigger("init");
+
+			this._data.core.original_container_html = this.element.find(" > ul > li").clone(true);
+			this._data.core.original_container_html
+				.find("li").addBack()
+				.contents().filter(function() {
+					return this.nodeType === 3 && (!this.nodeValue || /^\s+$/.test(this.nodeValue));
+				})
+				.remove();
+			this.element.html("<"+"ul class='jstree-container-ul jstree-children' role='group'><"+"li id='j"+this._id+"_loading' class='jstree-initial-node jstree-loading jstree-leaf jstree-last' role='tree-item'><i class='jstree-icon jstree-ocl'></i><"+"a class='jstree-anchor' href='#'><i class='jstree-icon jstree-themeicon-hidden'></i>" + this.get_string("Loading ...") + "</a></li></ul>");
+			this.element.attr('aria-activedescendant','j' + this._id + '_loading');
+			this._data.core.li_height = this.get_container_ul().children("li").first().height() || 24;
+			/**
+			 * triggered after the loading text is shown and before loading starts
+			 * @event
+			 * @name loading.jstree
+			 */
+			this.trigger("loading");
+			this.load_node('#');
+		},
+		/**
+		 * destroy an instance
+		 * @name destroy()
+		 * @param  {Boolean} keep_html if not set to `true` the container will be emptied, otherwise the current DOM elements will be kept intact
+		 */
+		destroy : function (keep_html) {
+			if(this._wrk) {
+				try {
+					window.URL.revokeObjectURL(this._wrk);
+					this._wrk = null;
+				}
+				catch (ignore) { }
+			}
+			if(!keep_html) { this.element.empty(); }
+			this.teardown();
+		},
+		/**
+		 * part of the destroying of an instance. Used internally.
+		 * @private
+		 * @name teardown()
+		 */
+		teardown : function () {
+			this.unbind();
+			this.element
+				.removeClass('jstree')
+				.removeData('jstree')
+				.find("[class^='jstree']")
+					.addBack()
+					.attr("class", function () { return this.className.replace(/jstree[^ ]*|$/ig,''); });
+			this.element = null;
+		},
+		/**
+		 * bind all events. Used internally.
+		 * @private
+		 * @name bind()
+		 */
+		bind : function () {
+			var word = '',
+				tout = null,
+				was_click = 0;
+			this.element
+				.on("dblclick.jstree", function () {
+						if(document.selection && document.selection.empty) {
+							document.selection.empty();
+						}
+						else {
+							if(window.getSelection) {
+								var sel = window.getSelection();
+								try {
+									sel.removeAllRanges();
+									sel.collapse();
+								} catch (ignore) { }
+							}
+						}
+					})
+				.on("mousedown.jstree", $.proxy(function (e) {
+						if(e.target === this.element[0]) {
+							e.preventDefault(); // prevent losing focus when clicking scroll arrows (FF, Chrome)
+							was_click = +(new Date()); // ie does not allow to prevent losing focus
+						}
+					}, this))
+				.on("mousedown.jstree", ".jstree-ocl", function (e) {
+						e.preventDefault(); // prevent any node inside from losing focus when clicking the open/close icon
+					})
+				.on("click.jstree", ".jstree-ocl", $.proxy(function (e) {
+						this.toggle_node(e.target);
+					}, this))
+				.on("dblclick.jstree", ".jstree-anchor", $.proxy(function (e) {
+						if(this.settings.core.dblclick_toggle) {
+							this.toggle_node(e.target);
+						}
+					}, this))
+				.on("click.jstree", ".jstree-anchor", $.proxy(function (e) {
+						e.preventDefault();
+						if(e.currentTarget !== document.activeElement) { $(e.currentTarget).focus(); }
+						this.activate_node(e.currentTarget, e);
+					}, this))
+				.on('keydown.jstree', '.jstree-anchor', $.proxy(function (e) {
+						if(e.target.tagName === "INPUT") { return true; }
+						var o = null;
+						if(this._data.core.rtl) {
+							if(e.which === 37) { e.which = 39; }
+							else if(e.which === 39) { e.which = 37; }
+						}
+						switch(e.which) {
+							case 32: // aria defines space only with Ctrl
+								if(e.ctrlKey) {
+									e.type = "click";
+									$(e.currentTarget).trigger(e);
+								}
+								break;
+							case 13: // enter
+								e.type = "click";
+								$(e.currentTarget).trigger(e);
+								break;
+							case 37: // right
+								e.preventDefault();
+								if(this.is_open(e.currentTarget)) {
+									this.close_node(e.currentTarget);
+								}
+								else {
+									o = this.get_parent(e.currentTarget);
+									if(o && o.id !== '#') { this.get_node(o, true).children('.jstree-anchor').focus(); }
+								}
+								break;
+							case 38: // up
+								e.preventDefault();
+								o = this.get_prev_dom(e.currentTarget);
+								if(o && o.length) { o.children('.jstree-anchor').focus(); }
+								break;
+							case 39: // left
+								e.preventDefault();
+								if(this.is_closed(e.currentTarget)) {
+									this.open_node(e.currentTarget, function (o) { this.get_node(o, true).children('.jstree-anchor').focus(); });
+								}
+								else if (this.is_open(e.currentTarget)) {
+									o = this.get_node(e.currentTarget, true).children('.jstree-children')[0];
+									if(o) { $(this._firstChild(o)).children('.jstree-anchor').focus(); }
+								}
+								break;
+							case 40: // down
+								e.preventDefault();
+								o = this.get_next_dom(e.currentTarget);
+								if(o && o.length) { o.children('.jstree-anchor').focus(); }
+								break;
+							case 106: // aria defines * on numpad as open_all - not very common
+								this.open_all();
+								break;
+							case 36: // home
+								e.preventDefault();
+								o = this._firstChild(this.get_container_ul()[0]);
+								if(o) { $(o).children('.jstree-anchor').filter(':visible').focus(); }
+								break;
+							case 35: // end
+								e.preventDefault();
+								this.element.find('.jstree-anchor').filter(':visible').last().focus();
+								break;
+							/*
+							// delete
+							case 46:
+								e.preventDefault();
+								o = this.get_node(e.currentTarget);
+								if(o && o.id && o.id !== '#') {
+									o = this.is_selected(o) ? this.get_selected() : o;
+									this.delete_node(o);
+								}
+								break;
+							// f2
+							case 113:
+								e.preventDefault();
+								o = this.get_node(e.currentTarget);
+								if(o && o.id && o.id !== '#') {
+									// this.edit(o);
+								}
+								break;
+							default:
+								// console.log(e.which);
+								break;
+							*/
+						}
+					}, this))
+				.on("load_node.jstree", $.proxy(function (e, data) {
+						if(data.status) {
+							if(data.node.id === '#' && !this._data.core.loaded) {
+								this._data.core.loaded = true;
+								if(this._firstChild(this.get_container_ul()[0])) {
+									this.element.attr('aria-activedescendant',this._firstChild(this.get_container_ul()[0]).id);
+								}
+								/**
+								 * triggered after the root node is loaded for the first time
+								 * @event
+								 * @name loaded.jstree
+								 */
+								this.trigger("loaded");
+							}
+							if(!this._data.core.ready) {
+								setTimeout($.proxy(function() {
+									if(!this.get_container_ul().find('.jstree-loading').length) {
+										this._data.core.ready = true;
+										if(this._data.core.selected.length) {
+											if(this.settings.core.expand_selected_onload) {
+												var tmp = [], i, j;
+												for(i = 0, j = this._data.core.selected.length; i < j; i++) {
+													tmp = tmp.concat(this._model.data[this._data.core.selected[i]].parents);
+												}
+												tmp = $.vakata.array_unique(tmp);
+												for(i = 0, j = tmp.length; i < j; i++) {
+													this.open_node(tmp[i], false, 0);
+												}
+											}
+											this.trigger('changed', { 'action' : 'ready', 'selected' : this._data.core.selected });
+										}
+										/**
+										 * triggered after all nodes are finished loading
+										 * @event
+										 * @name ready.jstree
+										 */
+										this.trigger("ready");
+									}
+								}, this), 0);
+							}
+						}
+					}, this))
+				// quick searching when the tree is focused
+				.on('keypress.jstree', $.proxy(function (e) {
+						if(e.target.tagName === "INPUT") { return true; }
+						if(tout) { clearTimeout(tout); }
+						tout = setTimeout(function () {
+							word = '';
+						}, 500);
+
+						var chr = String.fromCharCode(e.which).toLowerCase(),
+							col = this.element.find('.jstree-anchor').filter(':visible'),
+							ind = col.index(document.activeElement) || 0,
+							end = false;
+						word += chr;
+
+						// match for whole word from current node down (including the current node)
+						if(word.length > 1) {
+							col.slice(ind).each($.proxy(function (i, v) {
+								if($(v).text().toLowerCase().indexOf(word) === 0) {
+									$(v).focus();
+									end = true;
+									return false;
+								}
+							}, this));
+							if(end) { return; }
+
+							// match for whole word from the beginning of the tree
+							col.slice(0, ind).each($.proxy(function (i, v) {
+								if($(v).text().toLowerCase().indexOf(word) === 0) {
+									$(v).focus();
+									end = true;
+									return false;
+								}
+							}, this));
+							if(end) { return; }
+						}
+						// list nodes that start with that letter (only if word consists of a single char)
+						if(new RegExp('^' + chr + '+$').test(word)) {
+							// search for the next node starting with that letter
+							col.slice(ind + 1).each($.proxy(function (i, v) {
+								if($(v).text().toLowerCase().charAt(0) === chr) {
+									$(v).focus();
+									end = true;
+									return false;
+								}
+							}, this));
+							if(end) { return; }
+
+							// search from the beginning
+							col.slice(0, ind + 1).each($.proxy(function (i, v) {
+								if($(v).text().toLowerCase().charAt(0) === chr) {
+									$(v).focus();
+									end = true;
+									return false;
+								}
+							}, this));
+							if(end) { return; }
+						}
+					}, this))
+				// THEME RELATED
+				.on("init.jstree", $.proxy(function () {
+						var s = this.settings.core.themes;
+						this._data.core.themes.dots			= s.dots;
+						this._data.core.themes.stripes		= s.stripes;
+						this._data.core.themes.icons		= s.icons;
+						this.set_theme(s.name || "default", s.url);
+						this.set_theme_variant(s.variant);
+					}, this))
+				.on("loading.jstree", $.proxy(function () {
+						this[ this._data.core.themes.dots ? "show_dots" : "hide_dots" ]();
+						this[ this._data.core.themes.icons ? "show_icons" : "hide_icons" ]();
+						this[ this._data.core.themes.stripes ? "show_stripes" : "hide_stripes" ]();
+					}, this))
+				.on('blur.jstree', '.jstree-anchor', $.proxy(function (e) {
+						this._data.core.focused = null;
+						$(e.currentTarget).filter('.jstree-hovered').mouseleave();
+						this.element.attr('tabindex', '0');
+					}, this))
+				.on('focus.jstree', '.jstree-anchor', $.proxy(function (e) {
+						var tmp = this.get_node(e.currentTarget);
+						if(tmp && tmp.id) {
+							this._data.core.focused = tmp.id;
+						}
+						this.element.find('.jstree-hovered').not(e.currentTarget).mouseleave();
+						$(e.currentTarget).mouseenter();
+						this.element.attr('tabindex', '-1');
+					}, this))
+				.on('focus.jstree', $.proxy(function () {
+						if(+(new Date()) - was_click > 500 && !this._data.core.focused) {
+							was_click = 0;
+							this.get_node(this.element.attr('aria-activedescendant'), true).find('> .jstree-anchor').focus();
+						}
+					}, this))
+				.on('mouseenter.jstree', '.jstree-anchor', $.proxy(function (e) {
+						this.hover_node(e.currentTarget);
+					}, this))
+				.on('mouseleave.jstree', '.jstree-anchor', $.proxy(function (e) {
+						this.dehover_node(e.currentTarget);
+					}, this));
+		},
+		/**
+		 * part of the destroying of an instance. Used internally.
+		 * @private
+		 * @name unbind()
+		 */
+		unbind : function () {
+			this.element.off('.jstree');
+			$(document).off('.jstree-' + this._id);
+		},
+		/**
+		 * trigger an event. Used internally.
+		 * @private
+		 * @name trigger(ev [, data])
+		 * @param  {String} ev the name of the event to trigger
+		 * @param  {Object} data additional data to pass with the event
+		 */
+		trigger : function (ev, data) {
+			if(!data) {
+				data = {};
+			}
+			data.instance = this;
+			this.element.triggerHandler(ev.replace('.jstree','') + '.jstree', data);
+		},
+		/**
+		 * returns the jQuery extended instance container
+		 * @name get_container()
+		 * @return {jQuery}
+		 */
+		get_container : function () {
+			return this.element;
+		},
+		/**
+		 * returns the jQuery extended main UL node inside the instance container. Used internally.
+		 * @private
+		 * @name get_container_ul()
+		 * @return {jQuery}
+		 */
+		get_container_ul : function () {
+			return this.element.children(".jstree-children").first();
+		},
+		/**
+		 * gets string replacements (localization). Used internally.
+		 * @private
+		 * @name get_string(key)
+		 * @param  {String} key
+		 * @return {String}
+		 */
+		get_string : function (key) {
+			var a = this.settings.core.strings;
+			if($.isFunction(a)) { return a.call(this, key); }
+			if(a && a[key]) { return a[key]; }
+			return key;
+		},
+		/**
+		 * gets the first child of a DOM node. Used internally.
+		 * @private
+		 * @name _firstChild(dom)
+		 * @param  {DOMElement} dom
+		 * @return {DOMElement}
+		 */
+		_firstChild : function (dom) {
+			dom = dom ? dom.firstChild : null;
+			while(dom !== null && dom.nodeType !== 1) {
+				dom = dom.nextSibling;
+			}
+			return dom;
+		},
+		/**
+		 * gets the next sibling of a DOM node. Used internally.
+		 * @private
+		 * @name _nextSibling(dom)
+		 * @param  {DOMElement} dom
+		 * @return {DOMElement}
+		 */
+		_nextSibling : function (dom) {
+			dom = dom ? dom.nextSibling : null;
+			while(dom !== null && dom.nodeType !== 1) {
+				dom = dom.nextSibling;
+			}
+			return dom;
+		},
+		/**
+		 * gets the previous sibling of a DOM node. Used internally.
+		 * @private
+		 * @name _previousSibling(dom)
+		 * @param  {DOMElement} dom
+		 * @return {DOMElement}
+		 */
+		_previousSibling : function (dom) {
+			dom = dom ? dom.previousSibling : null;
+			while(dom !== null && dom.nodeType !== 1) {
+				dom = dom.previousSibling;
+			}
+			return dom;
+		},
+		/**
+		 * get the JSON representation of a node (or the actual jQuery extended DOM node) by using any input (child DOM element, ID string, selector, etc)
+		 * @name get_node(obj [, as_dom])
+		 * @param  {mixed} obj
+		 * @param  {Boolean} as_dom
+		 * @return {Object|jQuery}
+		 */
+		get_node : function (obj, as_dom) {
+			if(obj && obj.id) {
+				obj = obj.id;
+			}
+			var dom;
+			try {
+				if(this._model.data[obj]) {
+					obj = this._model.data[obj];
+				}
+				else if(typeof obj === "string" && this._model.data[obj.replace(/^#/, '')]) {
+					obj = this._model.data[obj.replace(/^#/, '')];
+				}
+				else if(typeof obj === "string" && (dom = $('#' + obj.replace($.jstree.idregex,'\\$&'), this.element)).length && this._model.data[dom.closest('.jstree-node').attr('id')]) {
+					obj = this._model.data[dom.closest('.jstree-node').attr('id')];
+				}
+				else if((dom = $(obj, this.element)).length && this._model.data[dom.closest('.jstree-node').attr('id')]) {
+					obj = this._model.data[dom.closest('.jstree-node').attr('id')];
+				}
+				else if((dom = $(obj, this.element)).length && dom.hasClass('jstree')) {
+					obj = this._model.data['#'];
+				}
+				else {
+					return false;
+				}
+
+				if(as_dom) {
+					obj = obj.id === '#' ? this.element : $('#' + obj.id.replace($.jstree.idregex,'\\$&'), this.element);
+				}
+				return obj;
+			} catch (ex) { return false; }
+		},
+		/**
+		 * get the path to a node, either consisting of node texts, or of node IDs, optionally glued together (otherwise an array)
+		 * @name get_path(obj [, glue, ids])
+		 * @param  {mixed} obj the node
+		 * @param  {String} glue if you want the path as a string - pass the glue here (for example '/'), if a falsy value is supplied here, an array is returned
+		 * @param  {Boolean} ids if set to true build the path using ID, otherwise node text is used
+		 * @return {mixed}
+		 */
+		get_path : function (obj, glue, ids) {
+			obj = obj.parents ? obj : this.get_node(obj);
+			if(!obj || obj.id === '#' || !obj.parents) {
+				return false;
+			}
+			var i, j, p = [];
+			p.push(ids ? obj.id : obj.text);
+			for(i = 0, j = obj.parents.length; i < j; i++) {
+				p.push(ids ? obj.parents[i] : this.get_text(obj.parents[i]));
+			}
+			p = p.reverse().slice(1);
+			return glue ? p.join(glue) : p;
+		},
+		/**
+		 * get the next visible node that is below the `obj` node. If `strict` is set to `true` only sibling nodes are returned.
+		 * @name get_next_dom(obj [, strict])
+		 * @param  {mixed} obj
+		 * @param  {Boolean} strict
+		 * @return {jQuery}
+		 */
+		get_next_dom : function (obj, strict) {
+			var tmp;
+			obj = this.get_node(obj, true);
+			if(obj[0] === this.element[0]) {
+				tmp = this._firstChild(this.get_container_ul()[0]);
+				while (tmp && tmp.offsetHeight === 0) {
+					tmp = this._nextSibling(tmp);
+				}
+				return tmp ? $(tmp) : false;
+			}
+			if(!obj || !obj.length) {
+				return false;
+			}
+			if(strict) {
+				tmp = obj[0];
+				do {
+					tmp = this._nextSibling(tmp);
+				} while (tmp && tmp.offsetHeight === 0);
+				return tmp ? $(tmp) : false;
+			}
+			if(obj.hasClass("jstree-open")) {
+				tmp = this._firstChild(obj.children('.jstree-children')[0]);
+				while (tmp && tmp.offsetHeight === 0) {
+					tmp = this._nextSibling(tmp);
+				}
+				if(tmp !== null) {
+					return $(tmp);
+				}
+			}
+			tmp = obj[0];
+			do {
+				tmp = this._nextSibling(tmp);
+			} while (tmp && tmp.offsetHeight === 0);
+			if(tmp !== null) {
+				return $(tmp);
+			}
+			return obj.parentsUntil(".jstree",".jstree-node").next(".jstree-node:visible").first();
+		},
+		/**
+		 * get the previous visible node that is above the `obj` node. If `strict` is set to `true` only sibling nodes are returned.
+		 * @name get_prev_dom(obj [, strict])
+		 * @param  {mixed} obj
+		 * @param  {Boolean} strict
+		 * @return {jQuery}
+		 */
+		get_prev_dom : function (obj, strict) {
+			var tmp;
+			obj = this.get_node(obj, true);
+			if(obj[0] === this.element[0]) {
+				tmp = this.get_container_ul()[0].lastChild;
+				while (tmp && tmp.offsetHeight === 0) {
+					tmp = this._previousSibling(tmp);
+				}
+				return tmp ? $(tmp) : false;
+			}
+			if(!obj || !obj.length) {
+				return false;
+			}
+			if(strict) {
+				tmp = obj[0];
+				do {
+					tmp = this._previousSibling(tmp);
+				} while (tmp && tmp.offsetHeight === 0);
+				return tmp ? $(tmp) : false;
+			}
+			tmp = obj[0];
+			do {
+				tmp = this._previousSibling(tmp);
+			} while (tmp && tmp.offsetHeight === 0);
+			if(tmp !== null) {
+				obj = $(tmp);
+				while(obj.hasClass("jstree-open")) {
+					obj = obj.children(".jstree-children").first().children(".jstree-node:visible:last");
+				}
+				return obj;
+			}
+			tmp = obj[0].parentNode.parentNode;
+			return tmp && tmp.className && tmp.className.indexOf('jstree-node') !== -1 ? $(tmp) : false;
+		},
+		/**
+		 * get the parent ID of a node
+		 * @name get_parent(obj)
+		 * @param  {mixed} obj
+		 * @return {String}
+		 */
+		get_parent : function (obj) {
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') {
+				return false;
+			}
+			return obj.parent;
+		},
+		/**
+		 * get a jQuery collection of all the children of a node (node must be rendered)
+		 * @name get_children_dom(obj)
+		 * @param  {mixed} obj
+		 * @return {jQuery}
+		 */
+		get_children_dom : function (obj) {
+			obj = this.get_node(obj, true);
+			if(obj[0] === this.element[0]) {
+				return this.get_container_ul().children(".jstree-node");
+			}
+			if(!obj || !obj.length) {
+				return false;
+			}
+			return obj.children(".jstree-children").children(".jstree-node");
+		},
+		/**
+		 * checks if a node has children
+		 * @name is_parent(obj)
+		 * @param  {mixed} obj
+		 * @return {Boolean}
+		 */
+		is_parent : function (obj) {
+			obj = this.get_node(obj);
+			return obj && (obj.state.loaded === false || obj.children.length > 0);
+		},
+		/**
+		 * checks if a node is loaded (its children are available)
+		 * @name is_loaded(obj)
+		 * @param  {mixed} obj
+		 * @return {Boolean}
+		 */
+		is_loaded : function (obj) {
+			obj = this.get_node(obj);
+			return obj && obj.state.loaded;
+		},
+		/**
+		 * check if a node is currently loading (fetching children)
+		 * @name is_loading(obj)
+		 * @param  {mixed} obj
+		 * @return {Boolean}
+		 */
+		is_loading : function (obj) {
+			obj = this.get_node(obj);
+			return obj && obj.state && obj.state.loading;
+		},
+		/**
+		 * check if a node is opened
+		 * @name is_open(obj)
+		 * @param  {mixed} obj
+		 * @return {Boolean}
+		 */
+		is_open : function (obj) {
+			obj = this.get_node(obj);
+			return obj && obj.state.opened;
+		},
+		/**
+		 * check if a node is in a closed state
+		 * @name is_closed(obj)
+		 * @param  {mixed} obj
+		 * @return {Boolean}
+		 */
+		is_closed : function (obj) {
+			obj = this.get_node(obj);
+			return obj && this.is_parent(obj) && !obj.state.opened;
+		},
+		/**
+		 * check if a node has no children
+		 * @name is_leaf(obj)
+		 * @param  {mixed} obj
+		 * @return {Boolean}
+		 */
+		is_leaf : function (obj) {
+			return !this.is_parent(obj);
+		},
+		/**
+		 * loads a node (fetches its children using the `core.data` setting). Multiple nodes can be passed to by using an array.
+		 * @name load_node(obj [, callback])
+		 * @param  {mixed} obj
+		 * @param  {function} callback a function to be executed once loading is complete, the function is executed in the instance's scope and receives two arguments - the node and a boolean status
+		 * @return {Boolean}
+		 * @trigger load_node.jstree
+		 */
+		load_node : function (obj, callback) {
+			var k, l, i, j, c;
+			if($.isArray(obj)) {
+				this._load_nodes(obj.slice(), callback);
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj) {
+				if(callback) { callback.call(this, obj, false); }
+				return false;
+			}
+			// if(obj.state.loading) { } // the node is already loading - just wait for it to load and invoke callback? but if called implicitly it should be loaded again?
+			if(obj.state.loaded) {
+				obj.state.loaded = false;
+				for(k = 0, l = obj.children_d.length; k < l; k++) {
+					for(i = 0, j = obj.parents.length; i < j; i++) {
+						this._model.data[obj.parents[i]].children_d = $.vakata.array_remove_item(this._model.data[obj.parents[i]].children_d, obj.children_d[k]);
+					}
+					if(this._model.data[obj.children_d[k]].state.selected) {
+						c = true;
+						this._data.core.selected = $.vakata.array_remove_item(this._data.core.selected, obj.children_d[k]);
+					}
+					delete this._model.data[obj.children_d[k]];
+				}
+				obj.children = [];
+				obj.children_d = [];
+				if(c) {
+					this.trigger('changed', { 'action' : 'load_node', 'node' : obj, 'selected' : this._data.core.selected });
+				}
+			}
+			obj.state.loading = true;
+			this.get_node(obj, true).addClass("jstree-loading").attr('aria-busy',true);
+			this._load_node(obj, $.proxy(function (status) {
+				obj = this._model.data[obj.id];
+				obj.state.loading = false;
+				obj.state.loaded = status;
+				var dom = this.get_node(obj, true);
+				if(obj.state.loaded && !obj.children.length && dom && dom.length && !dom.hasClass('jstree-leaf')) {
+					dom.removeClass('jstree-closed jstree-open').addClass('jstree-leaf');
+				}
+				dom.removeClass("jstree-loading").attr('aria-busy',false);
+				/**
+				 * triggered after a node is loaded
+				 * @event
+				 * @name load_node.jstree
+				 * @param {Object} node the node that was loading
+				 * @param {Boolean} status was the node loaded successfully
+				 */
+				this.trigger('load_node', { "node" : obj, "status" : status });
+				if(callback) {
+					callback.call(this, obj, status);
+				}
+			}, this));
+			return true;
+		},
+		/**
+		 * load an array of nodes (will also load unavailable nodes as soon as the appear in the structure). Used internally.
+		 * @private
+		 * @name _load_nodes(nodes [, callback])
+		 * @param  {array} nodes
+		 * @param  {function} callback a function to be executed once loading is complete, the function is executed in the instance's scope and receives one argument - the array passed to _load_nodes
+		 */
+		_load_nodes : function (nodes, callback, is_callback) {
+			var r = true,
+				c = function () { this._load_nodes(nodes, callback, true); },
+				m = this._model.data, i, j;
+			for(i = 0, j = nodes.length; i < j; i++) {
+				if(m[nodes[i]] && (!m[nodes[i]].state.loaded || !is_callback)) {
+					if(!this.is_loading(nodes[i])) {
+						this.load_node(nodes[i], c);
+					}
+					r = false;
+				}
+			}
+			if(r) {
+				if(callback && !callback.done) {
+					callback.call(this, nodes);
+					callback.done = true;
+				}
+			}
+		},
+		/**
+		 * loads all unloaded nodes
+		 * @name load_all([obj, callback])
+		 * @param {mixed} obj the node to load recursively, omit to load all nodes in the tree
+		 * @param {function} callback a function to be executed once loading all the nodes is complete,
+		 * @trigger load_all.jstree
+		 */
+		load_all : function (obj, callback) {
+			if(!obj) { obj = '#'; }
+			obj = this.get_node(obj);
+			if(!obj) { return false; }
+			var to_load = [],
+				m = this._model.data,
+				c = m[obj.id].children_d,
+				i, j;
+			if(obj.state && !obj.state.loaded) {
+				to_load.push(obj.id);
+			}
+			for(i = 0, j = c.length; i < j; i++) {
+				if(m[c[i]] && m[c[i]].state && !m[c[i]].state.loaded) {
+					to_load.push(c[i]);
+				}
+			}
+			if(to_load.length) {
+				this._load_nodes(to_load, function () {
+					this.load_all(obj, callback);
+				});
+			}
+			else {
+				/**
+				 * triggered after a load_all call completes
+				 * @event
+				 * @name load_all.jstree
+				 * @param {Object} node the recursively loaded node
+				 */
+				if(callback) { callback.call(this, obj); }
+				this.trigger('load_all', { "node" : obj });
+			}
+		},
+		/**
+		 * handles the actual loading of a node. Used only internally.
+		 * @private
+		 * @name _load_node(obj [, callback])
+		 * @param  {mixed} obj
+		 * @param  {function} callback a function to be executed once loading is complete, the function is executed in the instance's scope and receives one argument - a boolean status
+		 * @return {Boolean}
+		 */
+		_load_node : function (obj, callback) {
+			var s = this.settings.core.data, t;
+			// use original HTML
+			if(!s) {
+				if(obj.id === '#') {
+					return this._append_html_data(obj, this._data.core.original_container_html.clone(true), function (status) {
+						callback.call(this, status);
+					});
+				}
+				else {
+					return callback.call(this, false);
+				}
+				// return callback.call(this, obj.id === '#' ? this._append_html_data(obj, this._data.core.original_container_html.clone(true)) : false);
+			}
+			if($.isFunction(s)) {
+				return s.call(this, obj, $.proxy(function (d) {
+					if(d === false) {
+						callback.call(this, false);
+					}
+					this[typeof d === 'string' ? '_append_html_data' : '_append_json_data'](obj, typeof d === 'string' ? $(d) : d, function (status) {
+						callback.call(this, status);
+					});
+					// return d === false ? callback.call(this, false) : callback.call(this, this[typeof d === 'string' ? '_append_html_data' : '_append_json_data'](obj, typeof d === 'string' ? $(d) : d));
+				}, this));
+			}
+			if(typeof s === 'object') {
+				if(s.url) {
+					s = $.extend(true, {}, s);
+					if($.isFunction(s.url)) {
+						s.url = s.url.call(this, obj);
+					}
+					if($.isFunction(s.data)) {
+						s.data = s.data.call(this, obj);
+					}
+					return $.ajax(s)
+						.done($.proxy(function (d,t,x) {
+								var type = x.getResponseHeader('Content-Type');
+								if(type.indexOf('json') !== -1 || typeof d === "object") {
+									return this._append_json_data(obj, d, function (status) { callback.call(this, status); });
+									//return callback.call(this, this._append_json_data(obj, d));
+								}
+								if(type.indexOf('html') !== -1 || typeof d === "string") {
+									return this._append_html_data(obj, $(d), function (status) { callback.call(this, status); });
+									// return callback.call(this, this._append_html_data(obj, $(d)));
+								}
+								this._data.core.last_error = { 'error' : 'ajax', 'plugin' : 'core', 'id' : 'core_04', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id, 'xhr' : x }) };
+								this.settings.core.error.call(this, this._data.core.last_error);
+								return callback.call(this, false);
+							}, this))
+						.fail($.proxy(function (f) {
+								callback.call(this, false);
+								this._data.core.last_error = { 'error' : 'ajax', 'plugin' : 'core', 'id' : 'core_04', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id, 'xhr' : f }) };
+								this.settings.core.error.call(this, this._data.core.last_error);
+							}, this));
+				}
+				t = ($.isArray(s) || $.isPlainObject(s)) ? JSON.parse(JSON.stringify(s)) : s;
+				if(obj.id === '#') {
+					return this._append_json_data(obj, t, function (status) {
+						callback.call(this, status);
+					});
+				}
+				else {
+					this._data.core.last_error = { 'error' : 'nodata', 'plugin' : 'core', 'id' : 'core_05', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id }) };
+					this.settings.core.error.call(this, this._data.core.last_error);
+					return callback.call(this, false);
+				}
+				//return callback.call(this, (obj.id === "#" ? this._append_json_data(obj, t) : false) );
+			}
+			if(typeof s === 'string') {
+				if(obj.id === '#') {
+					return this._append_html_data(obj, $(s), function (status) {
+						callback.call(this, status);
+					});
+				}
+				else {
+					this._data.core.last_error = { 'error' : 'nodata', 'plugin' : 'core', 'id' : 'core_06', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id }) };
+					this.settings.core.error.call(this, this._data.core.last_error);
+					return callback.call(this, false);
+				}
+				//return callback.call(this, (obj.id === "#" ? this._append_html_data(obj, $(s)) : false) );
+			}
+			return callback.call(this, false);
+		},
+		/**
+		 * adds a node to the list of nodes to redraw. Used only internally.
+		 * @private
+		 * @name _node_changed(obj [, callback])
+		 * @param  {mixed} obj
+		 */
+		_node_changed : function (obj) {
+			obj = this.get_node(obj);
+			if(obj) {
+				this._model.changed.push(obj.id);
+			}
+		},
+		/**
+		 * appends HTML content to the tree. Used internally.
+		 * @private
+		 * @name _append_html_data(obj, data)
+		 * @param  {mixed} obj the node to append to
+		 * @param  {String} data the HTML string to parse and append
+		 * @trigger model.jstree, changed.jstree
+		 */
+		_append_html_data : function (dom, data, cb) {
+			dom = this.get_node(dom);
+			dom.children = [];
+			dom.children_d = [];
+			var dat = data.is('ul') ? data.children() : data,
+				par = dom.id,
+				chd = [],
+				dpc = [],
+				m = this._model.data,
+				p = m[par],
+				s = this._data.core.selected.length,
+				tmp, i, j;
+			dat.each($.proxy(function (i, v) {
+				tmp = this._parse_model_from_html($(v), par, p.parents.concat());
+				if(tmp) {
+					chd.push(tmp);
+					dpc.push(tmp);
+					if(m[tmp].children_d.length) {
+						dpc = dpc.concat(m[tmp].children_d);
+					}
+				}
+			}, this));
+			p.children = chd;
+			p.children_d = dpc;
+			for(i = 0, j = p.parents.length; i < j; i++) {
+				m[p.parents[i]].children_d = m[p.parents[i]].children_d.concat(dpc);
+			}
+			/**
+			 * triggered when new data is inserted to the tree model
+			 * @event
+			 * @name model.jstree
+			 * @param {Array} nodes an array of node IDs
+			 * @param {String} parent the parent ID of the nodes
+			 */
+			this.trigger('model', { "nodes" : dpc, 'parent' : par });
+			if(par !== '#') {
+				this._node_changed(par);
+				this.redraw();
+			}
+			else {
+				this.get_container_ul().children('.jstree-initial-node').remove();
+				this.redraw(true);
+			}
+			if(this._data.core.selected.length !== s) {
+				this.trigger('changed', { 'action' : 'model', 'selected' : this._data.core.selected });
+			}
+			cb.call(this, true);
+		},
+		/**
+		 * appends JSON content to the tree. Used internally.
+		 * @private
+		 * @name _append_json_data(obj, data)
+		 * @param  {mixed} obj the node to append to
+		 * @param  {String} data the JSON object to parse and append
+		 * @param  {Boolean} force_processing internal param - do not set
+		 * @trigger model.jstree, changed.jstree
+		 */
+		_append_json_data : function (dom, data, cb, force_processing) {
+			dom = this.get_node(dom);
+			dom.children = [];
+			dom.children_d = [];
+			// *%$@!!!
+			if(data.d) {
+				data = data.d;
+				if(typeof data === "string") {
+					data = JSON.parse(data);
+				}
+			}
+			if(!$.isArray(data)) { data = [data]; }
+			var w = null,
+				args = {
+					'df'	: this._model.default_state,
+					'dat'	: data,
+					'par'	: dom.id,
+					'm'		: this._model.data,
+					't_id'	: this._id,
+					't_cnt'	: this._cnt,
+					'sel'	: this._data.core.selected
+				},
+				func = function (data, undefined) {
+					if(data.data) { data = data.data; }
+					var dat = data.dat,
+						par = data.par,
+						chd = [],
+						dpc = [],
+						add = [],
+						df = data.df,
+						t_id = data.t_id,
+						t_cnt = data.t_cnt,
+						m = data.m,
+						p = m[par],
+						sel = data.sel,
+						tmp, i, j, rslt,
+						parse_flat = function (d, p, ps) {
+							if(!ps) { ps = []; }
+							else { ps = ps.concat(); }
+							if(p) { ps.unshift(p); }
+							var tid = d.id.toString(),
+								i, j, c, e,
+								tmp = {
+									id			: tid,
+									text		: d.text || '',
+									icon		: d.icon !== undefined ? d.icon : true,
+									parent		: p,
+									parents		: ps,
+									children	: d.children || [],
+									children_d	: d.children_d || [],
+									data		: d.data,
+									state		: { },
+									li_attr		: { id : false },
+									a_attr		: { href : '#' },
+									original	: false
+								};
+							for(i in df) {
+								if(df.hasOwnProperty(i)) {
+									tmp.state[i] = df[i];
+								}
+							}
+							if(d && d.data && d.data.jstree && d.data.jstree.icon) {
+								tmp.icon = d.data.jstree.icon;
+							}
+							if(d && d.data) {
+								tmp.data = d.data;
+								if(d.data.jstree) {
+									for(i in d.data.jstree) {
+										if(d.data.jstree.hasOwnProperty(i)) {
+											tmp.state[i] = d.data.jstree[i];
+										}
+									}
+								}
+							}
+							if(d && typeof d.state === 'object') {
+								for (i in d.state) {
+									if(d.state.hasOwnProperty(i)) {
+										tmp.state[i] = d.state[i];
+									}
+								}
+							}
+							if(d && typeof d.li_attr === 'object') {
+								for (i in d.li_attr) {
+									if(d.li_attr.hasOwnProperty(i)) {
+										tmp.li_attr[i] = d.li_attr[i];
+									}
+								}
+							}
+							if(!tmp.li_attr.id) {
+								tmp.li_attr.id = tid;
+							}
+							if(d && typeof d.a_attr === 'object') {
+								for (i in d.a_attr) {
+									if(d.a_attr.hasOwnProperty(i)) {
+										tmp.a_attr[i] = d.a_attr[i];
+									}
+								}
+							}
+							if(d && d.children && d.children === true) {
+								tmp.state.loaded = false;
+								tmp.children = [];
+								tmp.children_d = [];
+							}
+							m[tmp.id] = tmp;
+							for(i = 0, j = tmp.children.length; i < j; i++) {
+								c = parse_flat(m[tmp.children[i]], tmp.id, ps);
+								e = m[c];
+								tmp.children_d.push(c);
+								if(e.children_d.length) {
+									tmp.children_d = tmp.children_d.concat(e.children_d);
+								}
+							}
+							delete d.data;
+							delete d.children;
+							m[tmp.id].original = d;
+							if(tmp.state.selected) {
+								add.push(tmp.id);
+							}
+							return tmp.id;
+						},
+						parse_nest = function (d, p, ps) {
+							if(!ps) { ps = []; }
+							else { ps = ps.concat(); }
+							if(p) { ps.unshift(p); }
+							var tid = false, i, j, c, e, tmp;
+							do {
+								tid = 'j' + t_id + '_' + (++t_cnt);
+							} while(m[tid]);
+
+							tmp = {
+								id			: false,
+								text		: typeof d === 'string' ? d : '',
+								icon		: typeof d === 'object' && d.icon !== undefined ? d.icon : true,
+								parent		: p,
+								parents		: ps,
+								children	: [],
+								children_d	: [],
+								data		: null,
+								state		: { },
+								li_attr		: { id : false },
+								a_attr		: { href : '#' },
+								original	: false
+							};
+							for(i in df) {
+								if(df.hasOwnProperty(i)) {
+									tmp.state[i] = df[i];
+								}
+							}
+							if(d && d.id) { tmp.id = d.id.toString(); }
+							if(d && d.text) { tmp.text = d.text; }
+							if(d && d.data && d.data.jstree && d.data.jstree.icon) {
+								tmp.icon = d.data.jstree.icon;
+							}
+							if(d && d.data) {
+								tmp.data = d.data;
+								if(d.data.jstree) {
+									for(i in d.data.jstree) {
+										if(d.data.jstree.hasOwnProperty(i)) {
+											tmp.state[i] = d.data.jstree[i];
+										}
+									}
+								}
+							}
+							if(d && typeof d.state === 'object') {
+								for (i in d.state) {
+									if(d.state.hasOwnProperty(i)) {
+										tmp.state[i] = d.state[i];
+									}
+								}
+							}
+							if(d && typeof d.li_attr === 'object') {
+								for (i in d.li_attr) {
+									if(d.li_attr.hasOwnProperty(i)) {
+										tmp.li_attr[i] = d.li_attr[i];
+									}
+								}
+							}
+							if(tmp.li_attr.id && !tmp.id) {
+								tmp.id = tmp.li_attr.id.toString();
+							}
+							if(!tmp.id) {
+								tmp.id = tid;
+							}
+							if(!tmp.li_attr.id) {
+								tmp.li_attr.id = tmp.id;
+							}
+							if(d && typeof d.a_attr === 'object') {
+								for (i in d.a_attr) {
+									if(d.a_attr.hasOwnProperty(i)) {
+										tmp.a_attr[i] = d.a_attr[i];
+									}
+								}
+							}
+							if(d && d.children && d.children.length) {
+								for(i = 0, j = d.children.length; i < j; i++) {
+									c = parse_nest(d.children[i], tmp.id, ps);
+									e = m[c];
+									tmp.children.push(c);
+									if(e.children_d.length) {
+										tmp.children_d = tmp.children_d.concat(e.children_d);
+									}
+								}
+								tmp.children_d = tmp.children_d.concat(tmp.children);
+							}
+							if(d && d.children && d.children === true) {
+								tmp.state.loaded = false;
+								tmp.children = [];
+								tmp.children_d = [];
+							}
+							delete d.data;
+							delete d.children;
+							tmp.original = d;
+							m[tmp.id] = tmp;
+							if(tmp.state.selected) {
+								add.push(tmp.id);
+							}
+							return tmp.id;
+						};
+
+					if(dat.length && dat[0].id !== undefined && dat[0].parent !== undefined) {
+						// Flat JSON support (for easy import from DB):
+						// 1) convert to object (foreach)
+						for(i = 0, j = dat.length; i < j; i++) {
+							if(!dat[i].children) {
+								dat[i].children = [];
+							}
+							m[dat[i].id.toString()] = dat[i];
+						}
+						// 2) populate children (foreach)
+						for(i = 0, j = dat.length; i < j; i++) {
+							m[dat[i].parent.toString()].children.push(dat[i].id.toString());
+							// populate parent.children_d
+							p.children_d.push(dat[i].id.toString());
+						}
+						// 3) normalize && populate parents and children_d with recursion
+						for(i = 0, j = p.children.length; i < j; i++) {
+							tmp = parse_flat(m[p.children[i]], par, p.parents.concat());
+							dpc.push(tmp);
+							if(m[tmp].children_d.length) {
+								dpc = dpc.concat(m[tmp].children_d);
+							}
+						}
+						for(i = 0, j = p.parents.length; i < j; i++) {
+							m[p.parents[i]].children_d = m[p.parents[i]].children_d.concat(dpc);
+						}
+						// ?) three_state selection - p.state.selected && t - (if three_state foreach(dat => ch) -> foreach(parents) if(parent.selected) child.selected = true;
+						rslt = {
+							'cnt' : t_cnt,
+							'mod' : m,
+							'sel' : sel,
+							'par' : par,
+							'dpc' : dpc,
+							'add' : add
+						};
+					}
+					else {
+						for(i = 0, j = dat.length; i < j; i++) {
+							tmp = parse_nest(dat[i], par, p.parents.concat());
+							if(tmp) {
+								chd.push(tmp);
+								dpc.push(tmp);
+								if(m[tmp].children_d.length) {
+									dpc = dpc.concat(m[tmp].children_d);
+								}
+							}
+						}
+						p.children = chd;
+						p.children_d = dpc;
+						for(i = 0, j = p.parents.length; i < j; i++) {
+							m[p.parents[i]].children_d = m[p.parents[i]].children_d.concat(dpc);
+						}
+						rslt = {
+							'cnt' : t_cnt,
+							'mod' : m,
+							'sel' : sel,
+							'par' : par,
+							'dpc' : dpc,
+							'add' : add
+						};
+					}
+					if(typeof window === 'undefined' || typeof window.document === 'undefined') {
+						postMessage(rslt);
+					}
+					else {
+						return rslt;
+					}
+				},
+				rslt = function (rslt, worker) {
+					this._cnt = rslt.cnt;
+					this._model.data = rslt.mod; // breaks the reference in load_node - careful
+
+					if(worker) {
+						var i, j, a = rslt.add, r = rslt.sel, s = this._data.core.selected.slice(), m = this._model.data;
+						// if selection was changed while calculating in worker
+						if(r.length !== s.length || $.vakata.array_unique(r.concat(s)).length !== r.length) {
+							// deselect nodes that are no longer selected
+							for(i = 0, j = r.length; i < j; i++) {
+								if($.inArray(r[i], a) === -1 && $.inArray(r[i], s) === -1) {
+									m[r[i]].state.selected = false;
+								}
+							}
+							// select nodes that were selected in the mean time
+							for(i = 0, j = s.length; i < j; i++) {
+								if($.inArray(s[i], r) === -1) {
+									m[s[i]].state.selected = true;
+								}
+							}
+						}
+					}
+					if(rslt.add.length) {
+						this._data.core.selected = this._data.core.selected.concat(rslt.add);
+					}
+
+					this.trigger('model', { "nodes" : rslt.dpc, 'parent' : rslt.par });
+
+					if(rslt.par !== '#') {
+						this._node_changed(rslt.par);
+						this.redraw();
+					}
+					else {
+						// this.get_container_ul().children('.jstree-initial-node').remove();
+						this.redraw(true);
+					}
+					if(rslt.add.length) {
+						this.trigger('changed', { 'action' : 'model', 'selected' : this._data.core.selected });
+					}
+					cb.call(this, true);
+				};
+			if(this.settings.core.worker && window.Blob && window.URL && window.Worker) {
+				try {
+					if(this._wrk === null) {
+						this._wrk = window.URL.createObjectURL(
+							new window.Blob(
+								['self.onmessage = ' + func.toString()],
+								{type:"text/javascript"}
+							)
+						);
+					}
+					if(!this._data.core.working || force_processing) {
+						this._data.core.working = true;
+						w = new window.Worker(this._wrk);
+						w.onmessage = $.proxy(function (e) {
+							rslt.call(this, e.data, true);
+							try { w.terminate(); w = null; } catch(ignore) { }
+							if(this._data.core.worker_queue.length) {
+								this._append_json_data.apply(this, this._data.core.worker_queue.shift());
+							}
+							else {
+								this._data.core.working = false;
+							}
+						}, this);
+						if(!args.par) {
+							if(this._data.core.worker_queue.length) {
+								this._append_json_data.apply(this, this._data.core.worker_queue.shift());
+							}
+							else {
+								this._data.core.working = false;
+							}
+						}
+						else {
+							w.postMessage(args);
+						}
+					}
+					else {
+						this._data.core.worker_queue.push([dom, data, cb, true]);
+					}
+				}
+				catch(e) {
+					rslt.call(this, func(args), false);
+					if(this._data.core.worker_queue.length) {
+						this._append_json_data.apply(this, this._data.core.worker_queue.shift());
+					}
+					else {
+						this._data.core.working = false;
+					}
+				}
+			}
+			else {
+				rslt.call(this, func(args), false);
+			}
+		},
+		/**
+		 * parses a node from a jQuery object and appends them to the in memory tree model. Used internally.
+		 * @private
+		 * @name _parse_model_from_html(d [, p, ps])
+		 * @param  {jQuery} d the jQuery object to parse
+		 * @param  {String} p the parent ID
+		 * @param  {Array} ps list of all parents
+		 * @return {String} the ID of the object added to the model
+		 */
+		_parse_model_from_html : function (d, p, ps) {
+			if(!ps) { ps = []; }
+			else { ps = [].concat(ps); }
+			if(p) { ps.unshift(p); }
+			var c, e, m = this._model.data,
+				data = {
+					id			: false,
+					text		: false,
+					icon		: true,
+					parent		: p,
+					parents		: ps,
+					children	: [],
+					children_d	: [],
+					data		: null,
+					state		: { },
+					li_attr		: { id : false },
+					a_attr		: { href : '#' },
+					original	: false
+				}, i, tmp, tid;
+			for(i in this._model.default_state) {
+				if(this._model.default_state.hasOwnProperty(i)) {
+					data.state[i] = this._model.default_state[i];
+				}
+			}
+			tmp = $.vakata.attributes(d, true);
+			$.each(tmp, function (i, v) {
+				v = $.trim(v);
+				if(!v.length) { return true; }
+				data.li_attr[i] = v;
+				if(i === 'id') {
+					data.id = v.toString();
+				}
+			});
+			tmp = d.children('a').first();
+			if(tmp.length) {
+				tmp = $.vakata.attributes(tmp, true);
+				$.each(tmp, function (i, v) {
+					v = $.trim(v);
+					if(v.length) {
+						data.a_attr[i] = v;
+					}
+				});
+			}
+			tmp = d.children("a").first().length ? d.children("a").first().clone() : d.clone();
+			tmp.children("ins, i, ul").remove();
+			tmp = tmp.html();
+			tmp = $('<div />').html(tmp);
+			data.text = this.settings.core.force_text ? tmp.text() : tmp.html();
+			tmp = d.data();
+			data.data = tmp ? $.extend(true, {}, tmp) : null;
+			data.state.opened = d.hasClass('jstree-open');
+			data.state.selected = d.children('a').hasClass('jstree-clicked');
+			data.state.disabled = d.children('a').hasClass('jstree-disabled');
+			if(data.data && data.data.jstree) {
+				for(i in data.data.jstree) {
+					if(data.data.jstree.hasOwnProperty(i)) {
+						data.state[i] = data.data.jstree[i];
+					}
+				}
+			}
+			tmp = d.children("a").children(".jstree-themeicon");
+			if(tmp.length) {
+				data.icon = tmp.hasClass('jstree-themeicon-hidden') ? false : tmp.attr('rel');
+			}
+			if(data.state.icon) {
+				data.icon = data.state.icon;
+			}
+			tmp = d.children("ul").children("li");
+			do {
+				tid = 'j' + this._id + '_' + (++this._cnt);
+			} while(m[tid]);
+			data.id = data.li_attr.id ? data.li_attr.id.toString() : tid;
+			if(tmp.length) {
+				tmp.each($.proxy(function (i, v) {
+					c = this._parse_model_from_html($(v), data.id, ps);
+					e = this._model.data[c];
+					data.children.push(c);
+					if(e.children_d.length) {
+						data.children_d = data.children_d.concat(e.children_d);
+					}
+				}, this));
+				data.children_d = data.children_d.concat(data.children);
+			}
+			else {
+				if(d.hasClass('jstree-closed')) {
+					data.state.loaded = false;
+				}
+			}
+			if(data.li_attr['class']) {
+				data.li_attr['class'] = data.li_attr['class'].replace('jstree-closed','').replace('jstree-open','');
+			}
+			if(data.a_attr['class']) {
+				data.a_attr['class'] = data.a_attr['class'].replace('jstree-clicked','').replace('jstree-disabled','');
+			}
+			m[data.id] = data;
+			if(data.state.selected) {
+				this._data.core.selected.push(data.id);
+			}
+			return data.id;
+		},
+		/**
+		 * parses a node from a JSON object (used when dealing with flat data, which has no nesting of children, but has id and parent properties) and appends it to the in memory tree model. Used internally.
+		 * @private
+		 * @name _parse_model_from_flat_json(d [, p, ps])
+		 * @param  {Object} d the JSON object to parse
+		 * @param  {String} p the parent ID
+		 * @param  {Array} ps list of all parents
+		 * @return {String} the ID of the object added to the model
+		 */
+		_parse_model_from_flat_json : function (d, p, ps) {
+			if(!ps) { ps = []; }
+			else { ps = ps.concat(); }
+			if(p) { ps.unshift(p); }
+			var tid = d.id.toString(),
+				m = this._model.data,
+				df = this._model.default_state,
+				i, j, c, e,
+				tmp = {
+					id			: tid,
+					text		: d.text || '',
+					icon		: d.icon !== undefined ? d.icon : true,
+					parent		: p,
+					parents		: ps,
+					children	: d.children || [],
+					children_d	: d.children_d || [],
+					data		: d.data,
+					state		: { },
+					li_attr		: { id : false },
+					a_attr		: { href : '#' },
+					original	: false
+				};
+			for(i in df) {
+				if(df.hasOwnProperty(i)) {
+					tmp.state[i] = df[i];
+				}
+			}
+			if(d && d.data && d.data.jstree && d.data.jstree.icon) {
+				tmp.icon = d.data.jstree.icon;
+			}
+			if(d && d.data) {
+				tmp.data = d.data;
+				if(d.data.jstree) {
+					for(i in d.data.jstree) {
+						if(d.data.jstree.hasOwnProperty(i)) {
+							tmp.state[i] = d.data.jstree[i];
+						}
+					}
+				}
+			}
+			if(d && typeof d.state === 'object') {
+				for (i in d.state) {
+					if(d.state.hasOwnProperty(i)) {
+						tmp.state[i] = d.state[i];
+					}
+				}
+			}
+			if(d && typeof d.li_attr === 'object') {
+				for (i in d.li_attr) {
+					if(d.li_attr.hasOwnProperty(i)) {
+						tmp.li_attr[i] = d.li_attr[i];
+					}
+				}
+			}
+			if(!tmp.li_attr.id) {
+				tmp.li_attr.id = tid;
+			}
+			if(d && typeof d.a_attr === 'object') {
+				for (i in d.a_attr) {
+					if(d.a_attr.hasOwnProperty(i)) {
+						tmp.a_attr[i] = d.a_attr[i];
+					}
+				}
+			}
+			if(d && d.children && d.children === true) {
+				tmp.state.loaded = false;
+				tmp.children = [];
+				tmp.children_d = [];
+			}
+			m[tmp.id] = tmp;
+			for(i = 0, j = tmp.children.length; i < j; i++) {
+				c = this._parse_model_from_flat_json(m[tmp.children[i]], tmp.id, ps);
+				e = m[c];
+				tmp.children_d.push(c);
+				if(e.children_d.length) {
+					tmp.children_d = tmp.children_d.concat(e.children_d);
+				}
+			}
+			delete d.data;
+			delete d.children;
+			m[tmp.id].original = d;
+			if(tmp.state.selected) {
+				this._data.core.selected.push(tmp.id);
+			}
+			return tmp.id;
+		},
+		/**
+		 * parses a node from a JSON object and appends it to the in memory tree model. Used internally.
+		 * @private
+		 * @name _parse_model_from_json(d [, p, ps])
+		 * @param  {Object} d the JSON object to parse
+		 * @param  {String} p the parent ID
+		 * @param  {Array} ps list of all parents
+		 * @return {String} the ID of the object added to the model
+		 */
+		_parse_model_from_json : function (d, p, ps) {
+			if(!ps) { ps = []; }
+			else { ps = ps.concat(); }
+			if(p) { ps.unshift(p); }
+			var tid = false, i, j, c, e, m = this._model.data, df = this._model.default_state, tmp;
+			do {
+				tid = 'j' + this._id + '_' + (++this._cnt);
+			} while(m[tid]);
+
+			tmp = {
+				id			: false,
+				text		: typeof d === 'string' ? d : '',
+				icon		: typeof d === 'object' && d.icon !== undefined ? d.icon : true,
+				parent		: p,
+				parents		: ps,
+				children	: [],
+				children_d	: [],
+				data		: null,
+				state		: { },
+				li_attr		: { id : false },
+				a_attr		: { href : '#' },
+				original	: false
+			};
+			for(i in df) {
+				if(df.hasOwnProperty(i)) {
+					tmp.state[i] = df[i];
+				}
+			}
+			if(d && d.id) { tmp.id = d.id.toString(); }
+			if(d && d.text) { tmp.text = d.text; }
+			if(d && d.data && d.data.jstree && d.data.jstree.icon) {
+				tmp.icon = d.data.jstree.icon;
+			}
+			if(d && d.data) {
+				tmp.data = d.data;
+				if(d.data.jstree) {
+					for(i in d.data.jstree) {
+						if(d.data.jstree.hasOwnProperty(i)) {
+							tmp.state[i] = d.data.jstree[i];
+						}
+					}
+				}
+			}
+			if(d && typeof d.state === 'object') {
+				for (i in d.state) {
+					if(d.state.hasOwnProperty(i)) {
+						tmp.state[i] = d.state[i];
+					}
+				}
+			}
+			if(d && typeof d.li_attr === 'object') {
+				for (i in d.li_attr) {
+					if(d.li_attr.hasOwnProperty(i)) {
+						tmp.li_attr[i] = d.li_attr[i];
+					}
+				}
+			}
+			if(tmp.li_attr.id && !tmp.id) {
+				tmp.id = tmp.li_attr.id.toString();
+			}
+			if(!tmp.id) {
+				tmp.id = tid;
+			}
+			if(!tmp.li_attr.id) {
+				tmp.li_attr.id = tmp.id;
+			}
+			if(d && typeof d.a_attr === 'object') {
+				for (i in d.a_attr) {
+					if(d.a_attr.hasOwnProperty(i)) {
+						tmp.a_attr[i] = d.a_attr[i];
+					}
+				}
+			}
+			if(d && d.children && d.children.length) {
+				for(i = 0, j = d.children.length; i < j; i++) {
+					c = this._parse_model_from_json(d.children[i], tmp.id, ps);
+					e = m[c];
+					tmp.children.push(c);
+					if(e.children_d.length) {
+						tmp.children_d = tmp.children_d.concat(e.children_d);
+					}
+				}
+				tmp.children_d = tmp.children_d.concat(tmp.children);
+			}
+			if(d && d.children && d.children === true) {
+				tmp.state.loaded = false;
+				tmp.children = [];
+				tmp.children_d = [];
+			}
+			delete d.data;
+			delete d.children;
+			tmp.original = d;
+			m[tmp.id] = tmp;
+			if(tmp.state.selected) {
+				this._data.core.selected.push(tmp.id);
+			}
+			return tmp.id;
+		},
+		/**
+		 * redraws all nodes that need to be redrawn. Used internally.
+		 * @private
+		 * @name _redraw()
+		 * @trigger redraw.jstree
+		 */
+		_redraw : function () {
+			var nodes = this._model.force_full_redraw ? this._model.data['#'].children.concat([]) : this._model.changed.concat([]),
+				f = document.createElement('UL'), tmp, i, j, fe = this._data.core.focused;
+			for(i = 0, j = nodes.length; i < j; i++) {
+				tmp = this.redraw_node(nodes[i], true, this._model.force_full_redraw);
+				if(tmp && this._model.force_full_redraw) {
+					f.appendChild(tmp);
+				}
+			}
+			if(this._model.force_full_redraw) {
+				f.className = this.get_container_ul()[0].className;
+				f.setAttribute('role','group');
+				this.element.empty().append(f);
+				//this.get_container_ul()[0].appendChild(f);
+			}
+			if(fe !== null) {
+				tmp = this.get_node(fe, true);
+				if(tmp && tmp.length && tmp.children('.jstree-anchor')[0] !== document.activeElement) {
+					tmp.children('.jstree-anchor').focus();
+				}
+				else {
+					this._data.core.focused = null;
+				}
+			}
+			this._model.force_full_redraw = false;
+			this._model.changed = [];
+			/**
+			 * triggered after nodes are redrawn
+			 * @event
+			 * @name redraw.jstree
+			 * @param {array} nodes the redrawn nodes
+			 */
+			this.trigger('redraw', { "nodes" : nodes });
+		},
+		/**
+		 * redraws all nodes that need to be redrawn or optionally - the whole tree
+		 * @name redraw([full])
+		 * @param {Boolean} full if set to `true` all nodes are redrawn.
+		 */
+		redraw : function (full) {
+			if(full) {
+				this._model.force_full_redraw = true;
+			}
+			//if(this._model.redraw_timeout) {
+			//	clearTimeout(this._model.redraw_timeout);
+			//}
+			//this._model.redraw_timeout = setTimeout($.proxy(this._redraw, this),0);
+			this._redraw();
+		},
+		/**
+		 * redraws a single node's children. Used internally.
+		 * @private
+		 * @name draw_children(node)
+		 * @param {mixed} node the node whose children will be redrawn
+		 */
+		draw_children : function (node) {
+			var obj = this.get_node(node),
+				i = false,
+				j = false,
+				k = false,
+				d = document;
+			if(!obj) { return false; }
+			if(obj.id === '#') { return this.redraw(true); }
+			node = this.get_node(node, true);
+			if(!node || !node.length) { return false; } // TODO: quick toggle
+
+			node.children('.jstree-children').remove();
+			node = node[0];
+			if(obj.children.length && obj.state.loaded) {
+				k = d.createElement('UL');
+				k.setAttribute('role', 'group');
+				k.className = 'jstree-children';
+				for(i = 0, j = obj.children.length; i < j; i++) {
+					k.appendChild(this.redraw_node(obj.children[i], true, true));
+				}
+				node.appendChild(k);
+			}
+		},
+		/**
+		 * redraws a single node. Used internally.
+		 * @private
+		 * @name redraw_node(node, deep, is_callback, force_render)
+		 * @param {mixed} node the node to redraw
+		 * @param {Boolean} deep should child nodes be redrawn too
+		 * @param {Boolean} is_callback is this a recursion call
+		 * @param {Boolean} force_render should children of closed parents be drawn anyway
+		 */
+		redraw_node : function (node, deep, is_callback, force_render) {
+			var obj = this.get_node(node),
+				par = false,
+				ind = false,
+				old = false,
+				i = false,
+				j = false,
+				k = false,
+				c = '',
+				d = document,
+				m = this._model.data,
+				f = false,
+				s = false,
+				tmp = null,
+				t = 0,
+				l = 0;
+			if(!obj) { return false; }
+			if(obj.id === '#') {  return this.redraw(true); }
+			deep = deep || obj.children.length === 0;
+			node = !document.querySelector ? document.getElementById(obj.id) : this.element[0].querySelector('#' + ("0123456789".indexOf(obj.id[0]) !== -1 ? '\\3' + obj.id[0] + ' ' + obj.id.substr(1).replace($.jstree.idregex,'\\$&') : obj.id.replace($.jstree.idregex,'\\$&')) ); //, this.element);
+			if(!node) {
+				deep = true;
+				//node = d.createElement('LI');
+				if(!is_callback) {
+					par = obj.parent !== '#' ? $('#' + obj.parent.replace($.jstree.idregex,'\\$&'), this.element)[0] : null;
+					if(par !== null && (!par || !m[obj.parent].state.opened)) {
+						return false;
+					}
+					ind = $.inArray(obj.id, par === null ? m['#'].children : m[obj.parent].children);
+				}
+			}
+			else {
+				node = $(node);
+				if(!is_callback) {
+					par = node.parent().parent()[0];
+					if(par === this.element[0]) {
+						par = null;
+					}
+					ind = node.index();
+				}
+				// m[obj.id].data = node.data(); // use only node's data, no need to touch jquery storage
+				if(!deep && obj.children.length && !node.children('.jstree-children').length) {
+					deep = true;
+				}
+				if(!deep) {
+					old = node.children('.jstree-children')[0];
+				}
+				f = node.children('.jstree-anchor')[0] === document.activeElement;
+				node.remove();
+				//node = d.createElement('LI');
+				//node = node[0];
+			}
+			node = _node.cloneNode(true);
+			// node is DOM, deep is boolean
+
+			c = 'jstree-node ';
+			for(i in obj.li_attr) {
+				if(obj.li_attr.hasOwnProperty(i)) {
+					if(i === 'id') { continue; }
+					if(i !== 'class') {
+						node.setAttribute(i, obj.li_attr[i]);
+					}
+					else {
+						c += obj.li_attr[i];
+					}
+				}
+			}
+			if(!obj.a_attr.id) {
+				obj.a_attr.id = obj.id + '_anchor';
+			}
+			node.setAttribute('aria-selected', !!obj.state.selected);
+			node.setAttribute('aria-level', obj.parents.length);
+			node.setAttribute('aria-labelledby', obj.a_attr.id);
+			if(obj.state.disabled) {
+				node.setAttribute('aria-disabled', true);
+			}
+
+			if(obj.state.loaded && !obj.children.length) {
+				c += ' jstree-leaf';
+			}
+			else {
+				c += obj.state.opened && obj.state.loaded ? ' jstree-open' : ' jstree-closed';
+				node.setAttribute('aria-expanded', (obj.state.opened && obj.state.loaded) );
+			}
+			if(obj.parent !== null && m[obj.parent].children[m[obj.parent].children.length - 1] === obj.id) {
+				c += ' jstree-last';
+			}
+			node.id = obj.id;
+			node.className = c;
+			c = ( obj.state.selected ? ' jstree-clicked' : '') + ( obj.state.disabled ? ' jstree-disabled' : '');
+			for(j in obj.a_attr) {
+				if(obj.a_attr.hasOwnProperty(j)) {
+					if(j === 'href' && obj.a_attr[j] === '#') { continue; }
+					if(j !== 'class') {
+						node.childNodes[1].setAttribute(j, obj.a_attr[j]);
+					}
+					else {
+						c += ' ' + obj.a_attr[j];
+					}
+				}
+			}
+			if(c.length) {
+				node.childNodes[1].className = 'jstree-anchor ' + c;
+			}
+			if((obj.icon && obj.icon !== true) || obj.icon === false) {
+				if(obj.icon === false) {
+					node.childNodes[1].childNodes[0].className += ' jstree-themeicon-hidden';
+				}
+				else if(obj.icon.indexOf('/') === -1 && obj.icon.indexOf('.') === -1) {
+					node.childNodes[1].childNodes[0].className += ' ' + obj.icon + ' jstree-themeicon-custom';
+				}
+				else {
+					node.childNodes[1].childNodes[0].style.backgroundImage = 'url('+obj.icon+')';
+					node.childNodes[1].childNodes[0].style.backgroundPosition = 'center center';
+					node.childNodes[1].childNodes[0].style.backgroundSize = 'auto';
+					node.childNodes[1].childNodes[0].className += ' jstree-themeicon-custom';
+				}
+			}
+
+			if(this.settings.core.force_text) {
+				node.childNodes[1].appendChild(d.createTextNode(obj.text));
+			}
+			else {
+				node.childNodes[1].innerHTML += obj.text;
+			}
+
+
+			if(deep && obj.children.length && (obj.state.opened || force_render) && obj.state.loaded) {
+				k = d.createElement('UL');
+				k.setAttribute('role', 'group');
+				k.className = 'jstree-children';
+				for(i = 0, j = obj.children.length; i < j; i++) {
+					k.appendChild(this.redraw_node(obj.children[i], deep, true));
+				}
+				node.appendChild(k);
+			}
+			if(old) {
+				node.appendChild(old);
+			}
+			if(!is_callback) {
+				// append back using par / ind
+				if(!par) {
+					par = this.element[0];
+				}
+				for(i = 0, j = par.childNodes.length; i < j; i++) {
+					if(par.childNodes[i] && par.childNodes[i].className && par.childNodes[i].className.indexOf('jstree-children') !== -1) {
+						tmp = par.childNodes[i];
+						break;
+					}
+				}
+				if(!tmp) {
+					tmp = d.createElement('UL');
+					tmp.setAttribute('role', 'group');
+					tmp.className = 'jstree-children';
+					par.appendChild(tmp);
+				}
+				par = tmp;
+
+				if(ind < par.childNodes.length) {
+					par.insertBefore(node, par.childNodes[ind]);
+				}
+				else {
+					par.appendChild(node);
+				}
+				if(f) {
+					t = this.element[0].scrollTop;
+					l = this.element[0].scrollLeft;
+					node.childNodes[1].focus();
+					this.element[0].scrollTop = t;
+					this.element[0].scrollLeft = l;
+				}
+			}
+			if(obj.state.opened && !obj.state.loaded) {
+				obj.state.opened = false;
+				setTimeout($.proxy(function () {
+					this.open_node(obj.id, false, 0);
+				}, this), 0);
+			}
+			return node;
+		},
+		/**
+		 * opens a node, revaling its children. If the node is not loaded it will be loaded and opened once ready.
+		 * @name open_node(obj [, callback, animation])
+		 * @param {mixed} obj the node to open
+		 * @param {Function} callback a function to execute once the node is opened
+		 * @param {Number} animation the animation duration in milliseconds when opening the node (overrides the `core.animation` setting). Use `false` for no animation.
+		 * @trigger open_node.jstree, after_open.jstree, before_open.jstree
+		 */
+		open_node : function (obj, callback, animation) {
+			var t1, t2, d, t;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.open_node(obj[t1], callback, animation);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') {
+				return false;
+			}
+			animation = animation === undefined ? this.settings.core.animation : animation;
+			if(!this.is_closed(obj)) {
+				if(callback) {
+					callback.call(this, obj, false);
+				}
+				return false;
+			}
+			if(!this.is_loaded(obj)) {
+				if(this.is_loading(obj)) {
+					return setTimeout($.proxy(function () {
+						this.open_node(obj, callback, animation);
+					}, this), 500);
+				}
+				this.load_node(obj, function (o, ok) {
+					return ok ? this.open_node(o, callback, animation) : (callback ? callback.call(this, o, false) : false);
+				});
+			}
+			else {
+				d = this.get_node(obj, true);
+				t = this;
+				if(d.length) {
+					if(animation && d.children(".jstree-children").length) {
+						d.children(".jstree-children").stop(true, true);
+					}
+					if(obj.children.length && !this._firstChild(d.children('.jstree-children')[0])) {
+						this.draw_children(obj);
+						//d = this.get_node(obj, true);
+					}
+					if(!animation) {
+						this.trigger('before_open', { "node" : obj });
+						d[0].className = d[0].className.replace('jstree-closed', 'jstree-open');
+						d[0].setAttribute("aria-expanded", true);
+					}
+					else {
+						this.trigger('before_open', { "node" : obj });
+						d
+							.children(".jstree-children").css("display","none").end()
+							.removeClass("jstree-closed").addClass("jstree-open").attr("aria-expanded", true)
+							.children(".jstree-children").stop(true, true)
+								.slideDown(animation, function () {
+									this.style.display = "";
+									t.trigger("after_open", { "node" : obj });
+								});
+					}
+				}
+				obj.state.opened = true;
+				if(callback) {
+					callback.call(this, obj, true);
+				}
+				if(!d.length) {
+					/**
+					 * triggered when a node is about to be opened (if the node is supposed to be in the DOM, it will be, but it won't be visible yet)
+					 * @event
+					 * @name before_open.jstree
+					 * @param {Object} node the opened node
+					 */
+					this.trigger('before_open', { "node" : obj });
+				}
+				/**
+				 * triggered when a node is opened (if there is an animation it will not be completed yet)
+				 * @event
+				 * @name open_node.jstree
+				 * @param {Object} node the opened node
+				 */
+				this.trigger('open_node', { "node" : obj });
+				if(!animation || !d.length) {
+					/**
+					 * triggered when a node is opened and the animation is complete
+					 * @event
+					 * @name after_open.jstree
+					 * @param {Object} node the opened node
+					 */
+					this.trigger("after_open", { "node" : obj });
+				}
+			}
+		},
+		/**
+		 * opens every parent of a node (node should be loaded)
+		 * @name _open_to(obj)
+		 * @param {mixed} obj the node to reveal
+		 * @private
+		 */
+		_open_to : function (obj) {
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') {
+				return false;
+			}
+			var i, j, p = obj.parents;
+			for(i = 0, j = p.length; i < j; i+=1) {
+				if(i !== '#') {
+					this.open_node(p[i], false, 0);
+				}
+			}
+			return $('#' + obj.id.replace($.jstree.idregex,'\\$&'), this.element);
+		},
+		/**
+		 * closes a node, hiding its children
+		 * @name close_node(obj [, animation])
+		 * @param {mixed} obj the node to close
+		 * @param {Number} animation the animation duration in milliseconds when closing the node (overrides the `core.animation` setting). Use `false` for no animation.
+		 * @trigger close_node.jstree, after_close.jstree
+		 */
+		close_node : function (obj, animation) {
+			var t1, t2, t, d;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.close_node(obj[t1], animation);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') {
+				return false;
+			}
+			if(this.is_closed(obj)) {
+				return false;
+			}
+			animation = animation === undefined ? this.settings.core.animation : animation;
+			t = this;
+			d = this.get_node(obj, true);
+			if(d.length) {
+				if(!animation) {
+					d[0].className = d[0].className.replace('jstree-open', 'jstree-closed');
+					d.attr("aria-expanded", false).children('.jstree-children').remove();
+				}
+				else {
+					d
+						.children(".jstree-children").attr("style","display:block !important").end()
+						.removeClass("jstree-open").addClass("jstree-closed").attr("aria-expanded", false)
+						.children(".jstree-children").stop(true, true).slideUp(animation, function () {
+							this.style.display = "";
+							d.children('.jstree-children').remove();
+							t.trigger("after_close", { "node" : obj });
+						});
+				}
+			}
+			obj.state.opened = false;
+			/**
+			 * triggered when a node is closed (if there is an animation it will not be complete yet)
+			 * @event
+			 * @name close_node.jstree
+			 * @param {Object} node the closed node
+			 */
+			this.trigger('close_node',{ "node" : obj });
+			if(!animation || !d.length) {
+				/**
+				 * triggered when a node is closed and the animation is complete
+				 * @event
+				 * @name after_close.jstree
+				 * @param {Object} node the closed node
+				 */
+				this.trigger("after_close", { "node" : obj });
+			}
+		},
+		/**
+		 * toggles a node - closing it if it is open, opening it if it is closed
+		 * @name toggle_node(obj)
+		 * @param {mixed} obj the node to toggle
+		 */
+		toggle_node : function (obj) {
+			var t1, t2;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.toggle_node(obj[t1]);
+				}
+				return true;
+			}
+			if(this.is_closed(obj)) {
+				return this.open_node(obj);
+			}
+			if(this.is_open(obj)) {
+				return this.close_node(obj);
+			}
+		},
+		/**
+		 * opens all nodes within a node (or the tree), revaling their children. If the node is not loaded it will be loaded and opened once ready.
+		 * @name open_all([obj, animation, original_obj])
+		 * @param {mixed} obj the node to open recursively, omit to open all nodes in the tree
+		 * @param {Number} animation the animation duration in milliseconds when opening the nodes, the default is no animation
+		 * @param {jQuery} reference to the node that started the process (internal use)
+		 * @trigger open_all.jstree
+		 */
+		open_all : function (obj, animation, original_obj) {
+			if(!obj) { obj = '#'; }
+			obj = this.get_node(obj);
+			if(!obj) { return false; }
+			var dom = obj.id === '#' ? this.get_container_ul() : this.get_node(obj, true), i, j, _this;
+			if(!dom.length) {
+				for(i = 0, j = obj.children_d.length; i < j; i++) {
+					if(this.is_closed(this._model.data[obj.children_d[i]])) {
+						this._model.data[obj.children_d[i]].state.opened = true;
+					}
+				}
+				return this.trigger('open_all', { "node" : obj });
+			}
+			original_obj = original_obj || dom;
+			_this = this;
+			dom = this.is_closed(obj) ? dom.find('.jstree-closed').addBack() : dom.find('.jstree-closed');
+			dom.each(function () {
+				_this.open_node(
+					this,
+					function(node, status) { if(status && this.is_parent(node)) { this.open_all(node, animation, original_obj); } },
+					animation || 0
+				);
+			});
+			if(original_obj.find('.jstree-closed').length === 0) {
+				/**
+				 * triggered when an `open_all` call completes
+				 * @event
+				 * @name open_all.jstree
+				 * @param {Object} node the opened node
+				 */
+				this.trigger('open_all', { "node" : this.get_node(original_obj) });
+			}
+		},
+		/**
+		 * closes all nodes within a node (or the tree), revaling their children
+		 * @name close_all([obj, animation])
+		 * @param {mixed} obj the node to close recursively, omit to close all nodes in the tree
+		 * @param {Number} animation the animation duration in milliseconds when closing the nodes, the default is no animation
+		 * @trigger close_all.jstree
+		 */
+		close_all : function (obj, animation) {
+			if(!obj) { obj = '#'; }
+			obj = this.get_node(obj);
+			if(!obj) { return false; }
+			var dom = obj.id === '#' ? this.get_container_ul() : this.get_node(obj, true),
+				_this = this, i, j;
+			if(!dom.length) {
+				for(i = 0, j = obj.children_d.length; i < j; i++) {
+					this._model.data[obj.children_d[i]].state.opened = false;
+				}
+				return this.trigger('close_all', { "node" : obj });
+			}
+			dom = this.is_open(obj) ? dom.find('.jstree-open').addBack() : dom.find('.jstree-open');
+			$(dom.get().reverse()).each(function () { _this.close_node(this, animation || 0); });
+			/**
+			 * triggered when an `close_all` call completes
+			 * @event
+			 * @name close_all.jstree
+			 * @param {Object} node the closed node
+			 */
+			this.trigger('close_all', { "node" : obj });
+		},
+		/**
+		 * checks if a node is disabled (not selectable)
+		 * @name is_disabled(obj)
+		 * @param  {mixed} obj
+		 * @return {Boolean}
+		 */
+		is_disabled : function (obj) {
+			obj = this.get_node(obj);
+			return obj && obj.state && obj.state.disabled;
+		},
+		/**
+		 * enables a node - so that it can be selected
+		 * @name enable_node(obj)
+		 * @param {mixed} obj the node to enable
+		 * @trigger enable_node.jstree
+		 */
+		enable_node : function (obj) {
+			var t1, t2;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.enable_node(obj[t1]);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') {
+				return false;
+			}
+			obj.state.disabled = false;
+			this.get_node(obj,true).children('.jstree-anchor').removeClass('jstree-disabled').attr('aria-disabled', false);
+			/**
+			 * triggered when an node is enabled
+			 * @event
+			 * @name enable_node.jstree
+			 * @param {Object} node the enabled node
+			 */
+			this.trigger('enable_node', { 'node' : obj });
+		},
+		/**
+		 * disables a node - so that it can not be selected
+		 * @name disable_node(obj)
+		 * @param {mixed} obj the node to disable
+		 * @trigger disable_node.jstree
+		 */
+		disable_node : function (obj) {
+			var t1, t2;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.disable_node(obj[t1]);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') {
+				return false;
+			}
+			obj.state.disabled = true;
+			this.get_node(obj,true).children('.jstree-anchor').addClass('jstree-disabled').attr('aria-disabled', true);
+			/**
+			 * triggered when an node is disabled
+			 * @event
+			 * @name disable_node.jstree
+			 * @param {Object} node the disabled node
+			 */
+			this.trigger('disable_node', { 'node' : obj });
+		},
+		/**
+		 * called when a node is selected by the user. Used internally.
+		 * @private
+		 * @name activate_node(obj, e)
+		 * @param {mixed} obj the node
+		 * @param {Object} e the related event
+		 * @trigger activate_node.jstree, changed.jstree
+		 */
+		activate_node : function (obj, e) {
+			if(this.is_disabled(obj)) {
+				return false;
+			}
+
+			// ensure last_clicked is still in the DOM, make it fresh (maybe it was moved?) and make sure it is still selected, if not - make last_clicked the last selected node
+			this._data.core.last_clicked = this._data.core.last_clicked && this._data.core.last_clicked.id !== undefined ? this.get_node(this._data.core.last_clicked.id) : null;
+			if(this._data.core.last_clicked && !this._data.core.last_clicked.state.selected) { this._data.core.last_clicked = null; }
+			if(!this._data.core.last_clicked && this._data.core.selected.length) { this._data.core.last_clicked = this.get_node(this._data.core.selected[this._data.core.selected.length - 1]); }
+
+			if(!this.settings.core.multiple || (!e.metaKey && !e.ctrlKey && !e.shiftKey) || (e.shiftKey && (!this._data.core.last_clicked || !this.get_parent(obj) || this.get_parent(obj) !== this._data.core.last_clicked.parent ) )) {
+				if(!this.settings.core.multiple && (e.metaKey || e.ctrlKey || e.shiftKey) && this.is_selected(obj)) {
+					this.deselect_node(obj, false, e);
+				}
+				else {
+					this.deselect_all(true);
+					this.select_node(obj, false, false, e);
+					this._data.core.last_clicked = this.get_node(obj);
+				}
+			}
+			else {
+				if(e.shiftKey) {
+					var o = this.get_node(obj).id,
+						l = this._data.core.last_clicked.id,
+						p = this.get_node(this._data.core.last_clicked.parent).children,
+						c = false,
+						i, j;
+					for(i = 0, j = p.length; i < j; i += 1) {
+						// separate IFs work whem o and l are the same
+						if(p[i] === o) {
+							c = !c;
+						}
+						if(p[i] === l) {
+							c = !c;
+						}
+						if(c || p[i] === o || p[i] === l) {
+							this.select_node(p[i], true, false, e);
+						}
+						else {
+							this.deselect_node(p[i], true, e);
+						}
+					}
+					this.trigger('changed', { 'action' : 'select_node', 'node' : this.get_node(obj), 'selected' : this._data.core.selected, 'event' : e });
+				}
+				else {
+					if(!this.is_selected(obj)) {
+						this.select_node(obj, false, false, e);
+					}
+					else {
+						this.deselect_node(obj, false, e);
+					}
+				}
+			}
+			/**
+			 * triggered when an node is clicked or intercated with by the user
+			 * @event
+			 * @name activate_node.jstree
+			 * @param {Object} node
+			 */
+			this.trigger('activate_node', { 'node' : this.get_node(obj) });
+		},
+		/**
+		 * applies the hover state on a node, called when a node is hovered by the user. Used internally.
+		 * @private
+		 * @name hover_node(obj)
+		 * @param {mixed} obj
+		 * @trigger hover_node.jstree
+		 */
+		hover_node : function (obj) {
+			obj = this.get_node(obj, true);
+			if(!obj || !obj.length || obj.children('.jstree-hovered').length) {
+				return false;
+			}
+			var o = this.element.find('.jstree-hovered'), t = this.element;
+			if(o && o.length) { this.dehover_node(o); }
+
+			obj.children('.jstree-anchor').addClass('jstree-hovered');
+			/**
+			 * triggered when an node is hovered
+			 * @event
+			 * @name hover_node.jstree
+			 * @param {Object} node
+			 */
+			this.trigger('hover_node', { 'node' : this.get_node(obj) });
+			setTimeout(function () { t.attr('aria-activedescendant', obj[0].id); }, 0);
+		},
+		/**
+		 * removes the hover state from a nodecalled when a node is no longer hovered by the user. Used internally.
+		 * @private
+		 * @name dehover_node(obj)
+		 * @param {mixed} obj
+		 * @trigger dehover_node.jstree
+		 */
+		dehover_node : function (obj) {
+			obj = this.get_node(obj, true);
+			if(!obj || !obj.length || !obj.children('.jstree-hovered').length) {
+				return false;
+			}
+			obj.children('.jstree-anchor').removeClass('jstree-hovered');
+			/**
+			 * triggered when an node is no longer hovered
+			 * @event
+			 * @name dehover_node.jstree
+			 * @param {Object} node
+			 */
+			this.trigger('dehover_node', { 'node' : this.get_node(obj) });
+		},
+		/**
+		 * select a node
+		 * @name select_node(obj [, supress_event, prevent_open])
+		 * @param {mixed} obj an array can be used to select multiple nodes
+		 * @param {Boolean} supress_event if set to `true` the `changed.jstree` event won't be triggered
+		 * @param {Boolean} prevent_open if set to `true` parents of the selected node won't be opened
+		 * @trigger select_node.jstree, changed.jstree
+		 */
+		select_node : function (obj, supress_event, prevent_open, e) {
+			var dom, t1, t2, th;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.select_node(obj[t1], supress_event, prevent_open, e);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') {
+				return false;
+			}
+			dom = this.get_node(obj, true);
+			if(!obj.state.selected) {
+				obj.state.selected = true;
+				this._data.core.selected.push(obj.id);
+				if(!prevent_open) {
+					dom = this._open_to(obj);
+				}
+				if(dom && dom.length) {
+					dom.attr('aria-selected', true).children('.jstree-anchor').addClass('jstree-clicked');
+				}
+				/**
+				 * triggered when an node is selected
+				 * @event
+				 * @name select_node.jstree
+				 * @param {Object} node
+				 * @param {Array} selected the current selection
+				 * @param {Object} event the event (if any) that triggered this select_node
+				 */
+				this.trigger('select_node', { 'node' : obj, 'selected' : this._data.core.selected, 'event' : e });
+				if(!supress_event) {
+					/**
+					 * triggered when selection changes
+					 * @event
+					 * @name changed.jstree
+					 * @param {Object} node
+					 * @param {Object} action the action that caused the selection to change
+					 * @param {Array} selected the current selection
+					 * @param {Object} event the event (if any) that triggered this changed event
+					 */
+					this.trigger('changed', { 'action' : 'select_node', 'node' : obj, 'selected' : this._data.core.selected, 'event' : e });
+				}
+			}
+		},
+		/**
+		 * deselect a node
+		 * @name deselect_node(obj [, supress_event])
+		 * @param {mixed} obj an array can be used to deselect multiple nodes
+		 * @param {Boolean} supress_event if set to `true` the `changed.jstree` event won't be triggered
+		 * @trigger deselect_node.jstree, changed.jstree
+		 */
+		deselect_node : function (obj, supress_event, e) {
+			var t1, t2, dom;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.deselect_node(obj[t1], supress_event, e);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') {
+				return false;
+			}
+			dom = this.get_node(obj, true);
+			if(obj.state.selected) {
+				obj.state.selected = false;
+				this._data.core.selected = $.vakata.array_remove_item(this._data.core.selected, obj.id);
+				if(dom.length) {
+					dom.attr('aria-selected', false).children('.jstree-anchor').removeClass('jstree-clicked');
+				}
+				/**
+				 * triggered when an node is deselected
+				 * @event
+				 * @name deselect_node.jstree
+				 * @param {Object} node
+				 * @param {Array} selected the current selection
+				 * @param {Object} event the event (if any) that triggered this deselect_node
+				 */
+				this.trigger('deselect_node', { 'node' : obj, 'selected' : this._data.core.selected, 'event' : e });
+				if(!supress_event) {
+					this.trigger('changed', { 'action' : 'deselect_node', 'node' : obj, 'selected' : this._data.core.selected, 'event' : e });
+				}
+			}
+		},
+		/**
+		 * select all nodes in the tree
+		 * @name select_all([supress_event])
+		 * @param {Boolean} supress_event if set to `true` the `changed.jstree` event won't be triggered
+		 * @trigger select_all.jstree, changed.jstree
+		 */
+		select_all : function (supress_event) {
+			var tmp = this._data.core.selected.concat([]), i, j;
+			this._data.core.selected = this._model.data['#'].children_d.concat();
+			for(i = 0, j = this._data.core.selected.length; i < j; i++) {
+				if(this._model.data[this._data.core.selected[i]]) {
+					this._model.data[this._data.core.selected[i]].state.selected = true;
+				}
+			}
+			this.redraw(true);
+			/**
+			 * triggered when all nodes are selected
+			 * @event
+			 * @name select_all.jstree
+			 * @param {Array} selected the current selection
+			 */
+			this.trigger('select_all', { 'selected' : this._data.core.selected });
+			if(!supress_event) {
+				this.trigger('changed', { 'action' : 'select_all', 'selected' : this._data.core.selected, 'old_selection' : tmp });
+			}
+		},
+		/**
+		 * deselect all selected nodes
+		 * @name deselect_all([supress_event])
+		 * @param {Boolean} supress_event if set to `true` the `changed.jstree` event won't be triggered
+		 * @trigger deselect_all.jstree, changed.jstree
+		 */
+		deselect_all : function (supress_event) {
+			var tmp = this._data.core.selected.concat([]), i, j;
+			for(i = 0, j = this._data.core.selected.length; i < j; i++) {
+				if(this._model.data[this._data.core.selected[i]]) {
+					this._model.data[this._data.core.selected[i]].state.selected = false;
+				}
+			}
+			this._data.core.selected = [];
+			this.element.find('.jstree-clicked').removeClass('jstree-clicked').parent().attr('aria-selected', false);
+			/**
+			 * triggered when all nodes are deselected
+			 * @event
+			 * @name deselect_all.jstree
+			 * @param {Object} node the previous selection
+			 * @param {Array} selected the current selection
+			 */
+			this.trigger('deselect_all', { 'selected' : this._data.core.selected, 'node' : tmp });
+			if(!supress_event) {
+				this.trigger('changed', { 'action' : 'deselect_all', 'selected' : this._data.core.selected, 'old_selection' : tmp });
+			}
+		},
+		/**
+		 * checks if a node is selected
+		 * @name is_selected(obj)
+		 * @param  {mixed}  obj
+		 * @return {Boolean}
+		 */
+		is_selected : function (obj) {
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') {
+				return false;
+			}
+			return obj.state.selected;
+		},
+		/**
+		 * get an array of all selected nodes
+		 * @name get_selected([full])
+		 * @param  {mixed}  full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned
+		 * @return {Array}
+		 */
+		get_selected : function (full) {
+			return full ? $.map(this._data.core.selected, $.proxy(function (i) { return this.get_node(i); }, this)) : this._data.core.selected.slice();
+		},
+		/**
+		 * get an array of all top level selected nodes (ignoring children of selected nodes)
+		 * @name get_top_selected([full])
+		 * @param  {mixed}  full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned
+		 * @return {Array}
+		 */
+		get_top_selected : function (full) {
+			var tmp = this.get_selected(true),
+				obj = {}, i, j, k, l;
+			for(i = 0, j = tmp.length; i < j; i++) {
+				obj[tmp[i].id] = tmp[i];
+			}
+			for(i = 0, j = tmp.length; i < j; i++) {
+				for(k = 0, l = tmp[i].children_d.length; k < l; k++) {
+					if(obj[tmp[i].children_d[k]]) {
+						delete obj[tmp[i].children_d[k]];
+					}
+				}
+			}
+			tmp = [];
+			for(i in obj) {
+				if(obj.hasOwnProperty(i)) {
+					tmp.push(i);
+				}
+			}
+			return full ? $.map(tmp, $.proxy(function (i) { return this.get_node(i); }, this)) : tmp;
+		},
+		/**
+		 * get an array of all bottom level selected nodes (ignoring selected parents)
+		 * @name get_bottom_selected([full])
+		 * @param  {mixed}  full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned
+		 * @return {Array}
+		 */
+		get_bottom_selected : function (full) {
+			var tmp = this.get_selected(true),
+				obj = [], i, j;
+			for(i = 0, j = tmp.length; i < j; i++) {
+				if(!tmp[i].children.length) {
+					obj.push(tmp[i].id);
+				}
+			}
+			return full ? $.map(obj, $.proxy(function (i) { return this.get_node(i); }, this)) : obj;
+		},
+		/**
+		 * gets the current state of the tree so that it can be restored later with `set_state(state)`. Used internally.
+		 * @name get_state()
+		 * @private
+		 * @return {Object}
+		 */
+		get_state : function () {
+			var state	= {
+				'core' : {
+					'open' : [],
+					'scroll' : {
+						'left' : this.element.scrollLeft(),
+						'top' : this.element.scrollTop()
+					},
+					/*!
+					'themes' : {
+						'name' : this.get_theme(),
+						'icons' : this._data.core.themes.icons,
+						'dots' : this._data.core.themes.dots
+					},
+					*/
+					'selected' : []
+				}
+			}, i;
+			for(i in this._model.data) {
+				if(this._model.data.hasOwnProperty(i)) {
+					if(i !== '#') {
+						if(this._model.data[i].state.opened) {
+							state.core.open.push(i);
+						}
+						if(this._model.data[i].state.selected) {
+							state.core.selected.push(i);
+						}
+					}
+				}
+			}
+			return state;
+		},
+		/**
+		 * sets the state of the tree. Used internally.
+		 * @name set_state(state [, callback])
+		 * @private
+		 * @param {Object} state the state to restore
+		 * @param {Function} callback an optional function to execute once the state is restored.
+		 * @trigger set_state.jstree
+		 */
+		set_state : function (state, callback) {
+			if(state) {
+				if(state.core) {
+					var res, n, t, _this;
+					if(state.core.open) {
+						if(!$.isArray(state.core.open)) {
+							delete state.core.open;
+							this.set_state(state, callback);
+							return false;
+						}
+						res = true;
+						n = false;
+						t = this;
+						$.each(state.core.open.concat([]), function (i, v) {
+							n = t.get_node(v);
+							if(n) {
+								if(t.is_loaded(v)) {
+									if(t.is_closed(v)) {
+										t.open_node(v, false, 0);
+									}
+									if(state && state.core && state.core.open) {
+										$.vakata.array_remove_item(state.core.open, v);
+									}
+								}
+								else {
+									if(!t.is_loading(v)) {
+										t.open_node(v, $.proxy(function (o, s) {
+											if(!s && state && state.core && state.core.open) {
+												$.vakata.array_remove_item(state.core.open, o.id);
+											}
+											this.set_state(state, callback);
+										}, t), 0);
+									}
+									// there will be some async activity - so wait for it
+									res = false;
+								}
+							}
+						});
+						if(res) {
+							delete state.core.open;
+							this.set_state(state, callback);
+						}
+						return false;
+					}
+					if(state.core.scroll) {
+						if(state.core.scroll && state.core.scroll.left !== undefined) {
+							this.element.scrollLeft(state.core.scroll.left);
+						}
+						if(state.core.scroll && state.core.scroll.top !== undefined) {
+							this.element.scrollTop(state.core.scroll.top);
+						}
+						delete state.core.scroll;
+						this.set_state(state, callback);
+						return false;
+					}
+					/*!
+					if(state.core.themes) {
+						if(state.core.themes.name) {
+							this.set_theme(state.core.themes.name);
+						}
+						if(typeof state.core.themes.dots !== 'undefined') {
+							this[ state.core.themes.dots ? "show_dots" : "hide_dots" ]();
+						}
+						if(typeof state.core.themes.icons !== 'undefined') {
+							this[ state.core.themes.icons ? "show_icons" : "hide_icons" ]();
+						}
+						delete state.core.themes;
+						delete state.core.open;
+						this.set_state(state, callback);
+						return false;
+					}
+					*/
+					if(state.core.selected) {
+						_this = this;
+						this.deselect_all();
+						$.each(state.core.selected, function (i, v) {
+							_this.select_node(v);
+						});
+						delete state.core.selected;
+						this.set_state(state, callback);
+						return false;
+					}
+					if($.isEmptyObject(state.core)) {
+						delete state.core;
+						this.set_state(state, callback);
+						return false;
+					}
+				}
+				if($.isEmptyObject(state)) {
+					state = null;
+					if(callback) { callback.call(this); }
+					/**
+					 * triggered when a `set_state` call completes
+					 * @event
+					 * @name set_state.jstree
+					 */
+					this.trigger('set_state');
+					return false;
+				}
+				return true;
+			}
+			return false;
+		},
+		/**
+		 * refreshes the tree - all nodes are reloaded with calls to `load_node`.
+		 * @name refresh()
+		 * @param {Boolean} skip_loading an option to skip showing the loading indicator
+		 * @param {Mixed} forget_state if set to `true` state will not be reapplied, if set to a function (receiving the current state as argument) the result of that function will be used as state
+		 * @trigger refresh.jstree
+		 */
+		refresh : function (skip_loading, forget_state) {
+			this._data.core.state = forget_state === true ? {} : this.get_state();
+			if(forget_state && $.isFunction(forget_state)) { this._data.core.state = forget_state.call(this, this._data.core.state); }
+			this._cnt = 0;
+			this._model.data = {
+				'#' : {
+					id : '#',
+					parent : null,
+					parents : [],
+					children : [],
+					children_d : [],
+					state : { loaded : false }
+				}
+			};
+			var c = this.get_container_ul()[0].className;
+			if(!skip_loading) {
+				this.element.html("<"+"ul class='"+c+"' role='group'><"+"li class='jstree-initial-node jstree-loading jstree-leaf jstree-last' role='treeitem' id='j"+this._id+"_loading'><i class='jstree-icon jstree-ocl'></i><"+"a class='jstree-anchor' href='#'><i class='jstree-icon jstree-themeicon-hidden'></i>" + this.get_string("Loading ...") + "</a></li></ul>");
+				this.element.attr('aria-activedescendant','j'+this._id+'_loading');
+			}
+			this.load_node('#', function (o, s) {
+				if(s) {
+					this.get_container_ul()[0].className = c;
+					if(this._firstChild(this.get_container_ul()[0])) {
+						this.element.attr('aria-activedescendant',this._firstChild(this.get_container_ul()[0]).id);
+					}
+					this.set_state($.extend(true, {}, this._data.core.state), function () {
+						/**
+						 * triggered when a `refresh` call completes
+						 * @event
+						 * @name refresh.jstree
+						 */
+						this.trigger('refresh');
+					});
+				}
+				this._data.core.state = null;
+			});
+		},
+		/**
+		 * refreshes a node in the tree (reload its children) all opened nodes inside that node are reloaded with calls to `load_node`.
+		 * @name refresh_node(obj)
+		 * @param  {mixed} obj the node
+		 * @trigger refresh_node.jstree
+		 */
+		refresh_node : function (obj) {
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') { return false; }
+			var opened = [], to_load = [], s = this._data.core.selected.concat([]);
+			to_load.push(obj.id);
+			if(obj.state.opened === true) { opened.push(obj.id); }
+			this.get_node(obj, true).find('.jstree-open').each(function() { opened.push(this.id); });
+			this._load_nodes(to_load, $.proxy(function (nodes) {
+				this.open_node(opened, false, 0);
+				this.select_node(this._data.core.selected);
+				/**
+				 * triggered when a node is refreshed
+				 * @event
+				 * @name refresh_node.jstree
+				 * @param {Object} node - the refreshed node
+				 * @param {Array} nodes - an array of the IDs of the nodes that were reloaded
+				 */
+				this.trigger('refresh_node', { 'node' : obj, 'nodes' : nodes });
+			}, this));
+		},
+		/**
+		 * set (change) the ID of a node
+		 * @name set_id(obj, id)
+		 * @param  {mixed} obj the node
+		 * @param  {String} id the new ID
+		 * @return {Boolean}
+		 */
+		set_id : function (obj, id) {
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') { return false; }
+			var i, j, m = this._model.data;
+			id = id.toString();
+			// update parents (replace current ID with new one in children and children_d)
+			m[obj.parent].children[$.inArray(obj.id, m[obj.parent].children)] = id;
+			for(i = 0, j = obj.parents.length; i < j; i++) {
+				m[obj.parents[i]].children_d[$.inArray(obj.id, m[obj.parents[i]].children_d)] = id;
+			}
+			// update children (replace current ID with new one in parent and parents)
+			for(i = 0, j = obj.children.length; i < j; i++) {
+				m[obj.children[i]].parent = id;
+			}
+			for(i = 0, j = obj.children_d.length; i < j; i++) {
+				m[obj.children_d[i]].parents[$.inArray(obj.id, m[obj.children_d[i]].parents)] = id;
+			}
+			i = $.inArray(obj.id, this._data.core.selected);
+			if(i !== -1) { this._data.core.selected[i] = id; }
+			// update model and obj itself (obj.id, this._model.data[KEY])
+			i = this.get_node(obj.id, true);
+			if(i) {
+				i.attr('id', id);
+			}
+			delete m[obj.id];
+			obj.id = id;
+			m[id] = obj;
+			return true;
+		},
+		/**
+		 * get the text value of a node
+		 * @name get_text(obj)
+		 * @param  {mixed} obj the node
+		 * @return {String}
+		 */
+		get_text : function (obj) {
+			obj = this.get_node(obj);
+			return (!obj || obj.id === '#') ? false : obj.text;
+		},
+		/**
+		 * set the text value of a node. Used internally, please use `rename_node(obj, val)`.
+		 * @private
+		 * @name set_text(obj, val)
+		 * @param  {mixed} obj the node, you can pass an array to set the text on multiple nodes
+		 * @param  {String} val the new text value
+		 * @return {Boolean}
+		 * @trigger set_text.jstree
+		 */
+		set_text : function (obj, val) {
+			var t1, t2;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.set_text(obj[t1], val);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') { return false; }
+			obj.text = val;
+			if(this.get_node(obj, true).length) {
+				this.redraw_node(obj.id);
+			}
+			/**
+			 * triggered when a node text value is changed
+			 * @event
+			 * @name set_text.jstree
+			 * @param {Object} obj
+			 * @param {String} text the new value
+			 */
+			this.trigger('set_text',{ "obj" : obj, "text" : val });
+			return true;
+		},
+		/**
+		 * gets a JSON representation of a node (or the whole tree)
+		 * @name get_json([obj, options])
+		 * @param  {mixed} obj
+		 * @param  {Object} options
+		 * @param  {Boolean} options.no_state do not return state information
+		 * @param  {Boolean} options.no_id do not return ID
+		 * @param  {Boolean} options.no_children do not include children
+		 * @param  {Boolean} options.no_data do not include node data
+		 * @param  {Boolean} options.flat return flat JSON instead of nested
+		 * @return {Object}
+		 */
+		get_json : function (obj, options, flat) {
+			obj = this.get_node(obj || '#');
+			if(!obj) { return false; }
+			if(options && options.flat && !flat) { flat = []; }
+			var tmp = {
+				'id' : obj.id,
+				'text' : obj.text,
+				'icon' : this.get_icon(obj),
+				'li_attr' : $.extend(true, {}, obj.li_attr),
+				'a_attr' : $.extend(true, {}, obj.a_attr),
+				'state' : {},
+				'data' : options && options.no_data ? false : $.extend(true, {}, obj.data)
+				//( this.get_node(obj, true).length ? this.get_node(obj, true).data() : obj.data ),
+			}, i, j;
+			if(options && options.flat) {
+				tmp.parent = obj.parent;
+			}
+			else {
+				tmp.children = [];
+			}
+			if(!options || !options.no_state) {
+				for(i in obj.state) {
+					if(obj.state.hasOwnProperty(i)) {
+						tmp.state[i] = obj.state[i];
+					}
+				}
+			}
+			if(options && options.no_id) {
+				delete tmp.id;
+				if(tmp.li_attr && tmp.li_attr.id) {
+					delete tmp.li_attr.id;
+				}
+				if(tmp.a_attr && tmp.a_attr.id) {
+					delete tmp.a_attr.id;
+				}
+			}
+			if(options && options.flat && obj.id !== '#') {
+				flat.push(tmp);
+			}
+			if(!options || !options.no_children) {
+				for(i = 0, j = obj.children.length; i < j; i++) {
+					if(options && options.flat) {
+						this.get_json(obj.children[i], options, flat);
+					}
+					else {
+						tmp.children.push(this.get_json(obj.children[i], options));
+					}
+				}
+			}
+			return options && options.flat ? flat : (obj.id === '#' ? tmp.children : tmp);
+		},
+		/**
+		 * create a new node (do not confuse with load_node)
+		 * @name create_node([obj, node, pos, callback, is_loaded])
+		 * @param  {mixed}   par       the parent node (to create a root node use either "#" (string) or `null`)
+		 * @param  {mixed}   node      the data for the new node (a valid JSON object, or a simple string with the name)
+		 * @param  {mixed}   pos       the index at which to insert the node, "first" and "last" are also supported, default is "last"
+		 * @param  {Function} callback a function to be called once the node is created
+		 * @param  {Boolean} is_loaded internal argument indicating if the parent node was succesfully loaded
+		 * @return {String}            the ID of the newly create node
+		 * @trigger model.jstree, create_node.jstree
+		 */
+		create_node : function (par, node, pos, callback, is_loaded) {
+			if(par === null) { par = "#"; }
+			par = this.get_node(par);
+			if(!par) { return false; }
+			pos = pos === undefined ? "last" : pos;
+			if(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) {
+				return this.load_node(par, function () { this.create_node(par, node, pos, callback, true); });
+			}
+			if(!node) { node = { "text" : this.get_string('New node') }; }
+			if(typeof node === "string") { node = { "text" : node }; }
+			if(node.text === undefined) { node.text = this.get_string('New node'); }
+			var tmp, dpc, i, j;
+
+			if(par.id === '#') {
+				if(pos === "before") { pos = "first"; }
+				if(pos === "after") { pos = "last"; }
+			}
+			switch(pos) {
+				case "before":
+					tmp = this.get_node(par.parent);
+					pos = $.inArray(par.id, tmp.children);
+					par = tmp;
+					break;
+				case "after" :
+					tmp = this.get_node(par.parent);
+					pos = $.inArray(par.id, tmp.children) + 1;
+					par = tmp;
+					break;
+				case "inside":
+				case "first":
+					pos = 0;
+					break;
+				case "last":
+					pos = par.children.length;
+					break;
+				default:
+					if(!pos) { pos = 0; }
+					break;
+			}
+			if(pos > par.children.length) { pos = par.children.length; }
+			if(!node.id) { node.id = true; }
+			if(!this.check("create_node", node, par, pos)) {
+				this.settings.core.error.call(this, this._data.core.last_error);
+				return false;
+			}
+			if(node.id === true) { delete node.id; }
+			node = this._parse_model_from_json(node, par.id, par.parents.concat());
+			if(!node) { return false; }
+			tmp = this.get_node(node);
+			dpc = [];
+			dpc.push(node);
+			dpc = dpc.concat(tmp.children_d);
+			this.trigger('model', { "nodes" : dpc, "parent" : par.id });
+
+			par.children_d = par.children_d.concat(dpc);
+			for(i = 0, j = par.parents.length; i < j; i++) {
+				this._model.data[par.parents[i]].children_d = this._model.data[par.parents[i]].children_d.concat(dpc);
+			}
+			node = tmp;
+			tmp = [];
+			for(i = 0, j = par.children.length; i < j; i++) {
+				tmp[i >= pos ? i+1 : i] = par.children[i];
+			}
+			tmp[pos] = node.id;
+			par.children = tmp;
+
+			this.redraw_node(par, true);
+			if(callback) { callback.call(this, this.get_node(node)); }
+			/**
+			 * triggered when a node is created
+			 * @event
+			 * @name create_node.jstree
+			 * @param {Object} node
+			 * @param {String} parent the parent's ID
+			 * @param {Number} position the position of the new node among the parent's children
+			 */
+			this.trigger('create_node', { "node" : this.get_node(node), "parent" : par.id, "position" : pos });
+			return node.id;
+		},
+		/**
+		 * set the text value of a node
+		 * @name rename_node(obj, val)
+		 * @param  {mixed} obj the node, you can pass an array to rename multiple nodes to the same name
+		 * @param  {String} val the new text value
+		 * @return {Boolean}
+		 * @trigger rename_node.jstree
+		 */
+		rename_node : function (obj, val) {
+			var t1, t2, old;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.rename_node(obj[t1], val);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') { return false; }
+			old = obj.text;
+			if(!this.check("rename_node", obj, this.get_parent(obj), val)) {
+				this.settings.core.error.call(this, this._data.core.last_error);
+				return false;
+			}
+			this.set_text(obj, val); // .apply(this, Array.prototype.slice.call(arguments))
+			/**
+			 * triggered when a node is renamed
+			 * @event
+			 * @name rename_node.jstree
+			 * @param {Object} node
+			 * @param {String} text the new value
+			 * @param {String} old the old value
+			 */
+			this.trigger('rename_node', { "node" : obj, "text" : val, "old" : old });
+			return true;
+		},
+		/**
+		 * remove a node
+		 * @name delete_node(obj)
+		 * @param  {mixed} obj the node, you can pass an array to delete multiple nodes
+		 * @return {Boolean}
+		 * @trigger delete_node.jstree, changed.jstree
+		 */
+		delete_node : function (obj) {
+			var t1, t2, par, pos, tmp, i, j, k, l, c;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.delete_node(obj[t1]);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') { return false; }
+			par = this.get_node(obj.parent);
+			pos = $.inArray(obj.id, par.children);
+			c = false;
+			if(!this.check("delete_node", obj, par, pos)) {
+				this.settings.core.error.call(this, this._data.core.last_error);
+				return false;
+			}
+			if(pos !== -1) {
+				par.children = $.vakata.array_remove(par.children, pos);
+			}
+			tmp = obj.children_d.concat([]);
+			tmp.push(obj.id);
+			for(k = 0, l = tmp.length; k < l; k++) {
+				for(i = 0, j = obj.parents.length; i < j; i++) {
+					pos = $.inArray(tmp[k], this._model.data[obj.parents[i]].children_d);
+					if(pos !== -1) {
+						this._model.data[obj.parents[i]].children_d = $.vakata.array_remove(this._model.data[obj.parents[i]].children_d, pos);
+					}
+				}
+				if(this._model.data[tmp[k]].state.selected) {
+					c = true;
+					pos = $.inArray(tmp[k], this._data.core.selected);
+					if(pos !== -1) {
+						this._data.core.selected = $.vakata.array_remove(this._data.core.selected, pos);
+					}
+				}
+			}
+			/**
+			 * triggered when a node is deleted
+			 * @event
+			 * @name delete_node.jstree
+			 * @param {Object} node
+			 * @param {String} parent the parent's ID
+			 */
+			this.trigger('delete_node', { "node" : obj, "parent" : par.id });
+			if(c) {
+				this.trigger('changed', { 'action' : 'delete_node', 'node' : obj, 'selected' : this._data.core.selected, 'parent' : par.id });
+			}
+			for(k = 0, l = tmp.length; k < l; k++) {
+				delete this._model.data[tmp[k]];
+			}
+			this.redraw_node(par, true);
+			return true;
+		},
+		/**
+		 * check if an operation is premitted on the tree. Used internally.
+		 * @private
+		 * @name check(chk, obj, par, pos)
+		 * @param  {String} chk the operation to check, can be "create_node", "rename_node", "delete_node", "copy_node" or "move_node"
+		 * @param  {mixed} obj the node
+		 * @param  {mixed} par the parent
+		 * @param  {mixed} pos the position to insert at, or if "rename_node" - the new name
+		 * @param  {mixed} more some various additional information, for example if a "move_node" operations is triggered by DND this will be the hovered node
+		 * @return {Boolean}
+		 */
+		check : function (chk, obj, par, pos, more) {
+			obj = obj && obj.id ? obj : this.get_node(obj);
+			par = par && par.id ? par : this.get_node(par);
+			var tmp = chk.match(/^move_node|copy_node|create_node$/i) ? par : obj,
+				chc = this.settings.core.check_callback;
+			if(chk === "move_node" || chk === "copy_node") {
+				if((!more || !more.is_multi) && (obj.id === par.id || $.inArray(obj.id, par.children) === pos || $.inArray(par.id, obj.children_d) !== -1)) {
+					this._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_01', 'reason' : 'Moving parent inside child', 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };
+					return false;
+				}
+			}
+			if(tmp && tmp.data) { tmp = tmp.data; }
+			if(tmp && tmp.functions && (tmp.functions[chk] === false || tmp.functions[chk] === true)) {
+				if(tmp.functions[chk] === false) {
+					this._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_02', 'reason' : 'Node data prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };
+				}
+				return tmp.functions[chk];
+			}
+			if(chc === false || ($.isFunction(chc) && chc.call(this, chk, obj, par, pos, more) === false) || (chc && chc[chk] === false)) {
+				this._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_03', 'reason' : 'User config for core.check_callback prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };
+				return false;
+			}
+			return true;
+		},
+		/**
+		 * get the last error
+		 * @name last_error()
+		 * @return {Object}
+		 */
+		last_error : function () {
+			return this._data.core.last_error;
+		},
+		/**
+		 * move a node to a new parent
+		 * @name move_node(obj, par [, pos, callback, is_loaded])
+		 * @param  {mixed} obj the node to move, pass an array to move multiple nodes
+		 * @param  {mixed} par the new parent
+		 * @param  {mixed} pos the position to insert at (besides integer values, "first" and "last" are supported, as well as "before" and "after"), defaults to integer `0`
+		 * @param  {function} callback a function to call once the move is completed, receives 3 arguments - the node, the new parent and the position
+		 * @param  {Boolean} internal parameter indicating if the parent node has been loaded
+		 * @param  {Boolean} internal parameter indicating if the tree should be redrawn
+		 * @trigger move_node.jstree
+		 */
+		move_node : function (obj, par, pos, callback, is_loaded, skip_redraw) {
+			var t1, t2, old_par, old_pos, new_par, old_ins, is_multi, dpc, tmp, i, j, k, l, p;
+
+			par = this.get_node(par);
+			pos = pos === undefined ? 0 : pos;
+			if(!par) { return false; }
+			if(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) {
+				return this.load_node(par, function () { this.move_node(obj, par, pos, callback, true); });
+			}
+
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					if(this.move_node(obj[t1], par, pos, callback, is_loaded, true)) {
+						par = obj[t1];
+						pos = "after";
+					}
+				}
+				this.redraw();
+				return true;
+			}
+			obj = obj && obj.id ? obj : this.get_node(obj);
+
+			if(!obj || obj.id === '#') { return false; }
+
+			old_par = (obj.parent || '#').toString();
+			new_par = (!pos.toString().match(/^(before|after)$/) || par.id === '#') ? par : this.get_node(par.parent);
+			old_ins = obj.instance ? obj.instance : (this._model.data[obj.id] ? this : $.jstree.reference(obj.id));
+			is_multi = !old_ins || !old_ins._id || (this._id !== old_ins._id);
+			old_pos = old_ins && old_ins._id && old_par && old_ins._model.data[old_par] && old_ins._model.data[old_par].children ? $.inArray(obj.id, old_ins._model.data[old_par].children) : -1;
+			if(is_multi) {
+				if(this.copy_node(obj, par, pos, callback, is_loaded)) {
+					if(old_ins) { old_ins.delete_node(obj); }
+					return true;
+				}
+				return false;
+			}
+			//var m = this._model.data;
+			if(par.id === '#') {
+				if(pos === "before") { pos = "first"; }
+				if(pos === "after") { pos = "last"; }
+			}
+			switch(pos) {
+				case "before":
+					pos = $.inArray(par.id, new_par.children);
+					break;
+				case "after" :
+					pos = $.inArray(par.id, new_par.children) + 1;
+					break;
+				case "inside":
+				case "first":
+					pos = 0;
+					break;
+				case "last":
+					pos = new_par.children.length;
+					break;
+				default:
+					if(!pos) { pos = 0; }
+					break;
+			}
+			if(pos > new_par.children.length) { pos = new_par.children.length; }
+			if(!this.check("move_node", obj, new_par, pos, { 'core' : true, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id) })) {
+				this.settings.core.error.call(this, this._data.core.last_error);
+				return false;
+			}
+			if(obj.parent === new_par.id) {
+				dpc = new_par.children.concat();
+				tmp = $.inArray(obj.id, dpc);
+				if(tmp !== -1) {
+					dpc = $.vakata.array_remove(dpc, tmp);
+					if(pos > tmp) { pos--; }
+				}
+				tmp = [];
+				for(i = 0, j = dpc.length; i < j; i++) {
+					tmp[i >= pos ? i+1 : i] = dpc[i];
+				}
+				tmp[pos] = obj.id;
+				new_par.children = tmp;
+				this._node_changed(new_par.id);
+				this.redraw(new_par.id === '#');
+			}
+			else {
+				// clean old parent and up
+				tmp = obj.children_d.concat();
+				tmp.push(obj.id);
+				for(i = 0, j = obj.parents.length; i < j; i++) {
+					dpc = [];
+					p = old_ins._model.data[obj.parents[i]].children_d;
+					for(k = 0, l = p.length; k < l; k++) {
+						if($.inArray(p[k], tmp) === -1) {
+							dpc.push(p[k]);
+						}
+					}
+					old_ins._model.data[obj.parents[i]].children_d = dpc;
+				}
+				old_ins._model.data[old_par].children = $.vakata.array_remove_item(old_ins._model.data[old_par].children, obj.id);
+
+				// insert into new parent and up
+				for(i = 0, j = new_par.parents.length; i < j; i++) {
+					this._model.data[new_par.parents[i]].children_d = this._model.data[new_par.parents[i]].children_d.concat(tmp);
+				}
+				dpc = [];
+				for(i = 0, j = new_par.children.length; i < j; i++) {
+					dpc[i >= pos ? i+1 : i] = new_par.children[i];
+				}
+				dpc[pos] = obj.id;
+				new_par.children = dpc;
+				new_par.children_d.push(obj.id);
+				new_par.children_d = new_par.children_d.concat(obj.children_d);
+
+				// update object
+				obj.parent = new_par.id;
+				tmp = new_par.parents.concat();
+				tmp.unshift(new_par.id);
+				p = obj.parents.length;
+				obj.parents = tmp;
+
+				// update object children
+				tmp = tmp.concat();
+				for(i = 0, j = obj.children_d.length; i < j; i++) {
+					this._model.data[obj.children_d[i]].parents = this._model.data[obj.children_d[i]].parents.slice(0,p*-1);
+					Array.prototype.push.apply(this._model.data[obj.children_d[i]].parents, tmp);
+				}
+
+				if(old_par === '#' || new_par.id === '#') {
+					this._model.force_full_redraw = true;
+				}
+				if(!this._model.force_full_redraw) {
+					this._node_changed(old_par);
+					this._node_changed(new_par.id);
+				}
+				if(!skip_redraw) {
+					this.redraw();
+				}
+			}
+			if(callback) { callback.call(this, obj, new_par, pos); }
+			/**
+			 * triggered when a node is moved
+			 * @event
+			 * @name move_node.jstree
+			 * @param {Object} node
+			 * @param {String} parent the parent's ID
+			 * @param {Number} position the position of the node among the parent's children
+			 * @param {String} old_parent the old parent of the node
+			 * @param {Number} old_position the old position of the node
+			 * @param {Boolean} is_multi do the node and new parent belong to different instances
+			 * @param {jsTree} old_instance the instance the node came from
+			 * @param {jsTree} new_instance the instance of the new parent
+			 */
+			this.trigger('move_node', { "node" : obj, "parent" : new_par.id, "position" : pos, "old_parent" : old_par, "old_position" : old_pos, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id), 'old_instance' : old_ins, 'new_instance' : this });
+			return true;
+		},
+		/**
+		 * copy a node to a new parent
+		 * @name copy_node(obj, par [, pos, callback, is_loaded])
+		 * @param  {mixed} obj the node to copy, pass an array to copy multiple nodes
+		 * @param  {mixed} par the new parent
+		 * @param  {mixed} pos the position to insert at (besides integer values, "first" and "last" are supported, as well as "before" and "after"), defaults to integer `0`
+		 * @param  {function} callback a function to call once the move is completed, receives 3 arguments - the node, the new parent and the position
+		 * @param  {Boolean} internal parameter indicating if the parent node has been loaded
+		 * @param  {Boolean} internal parameter indicating if the tree should be redrawn
+		 * @trigger model.jstree copy_node.jstree
+		 */
+		copy_node : function (obj, par, pos, callback, is_loaded, skip_redraw) {
+			var t1, t2, dpc, tmp, i, j, node, old_par, new_par, old_ins, is_multi;
+
+			par = this.get_node(par);
+			pos = pos === undefined ? 0 : pos;
+			if(!par) { return false; }
+			if(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) {
+				return this.load_node(par, function () { this.copy_node(obj, par, pos, callback, true); });
+			}
+
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					tmp = this.copy_node(obj[t1], par, pos, callback, is_loaded, true);
+					if(tmp) {
+						par = tmp;
+						pos = "after";
+					}
+				}
+				this.redraw();
+				return true;
+			}
+			obj = obj && obj.id ? obj : this.get_node(obj);
+			if(!obj || obj.id === '#') { return false; }
+
+			old_par = (obj.parent || '#').toString();
+			new_par = (!pos.toString().match(/^(before|after)$/) || par.id === '#') ? par : this.get_node(par.parent);
+			old_ins = obj.instance ? obj.instance : (this._model.data[obj.id] ? this : $.jstree.reference(obj.id));
+			is_multi = !old_ins || !old_ins._id || (this._id !== old_ins._id);
+			if(par.id === '#') {
+				if(pos === "before") { pos = "first"; }
+				if(pos === "after") { pos = "last"; }
+			}
+			switch(pos) {
+				case "before":
+					pos = $.inArray(par.id, new_par.children);
+					break;
+				case "after" :
+					pos = $.inArray(par.id, new_par.children) + 1;
+					break;
+				case "inside":
+				case "first":
+					pos = 0;
+					break;
+				case "last":
+					pos = new_par.children.length;
+					break;
+				default:
+					if(!pos) { pos = 0; }
+					break;
+			}
+			if(pos > new_par.children.length) { pos = new_par.children.length; }
+			if(!this.check("copy_node", obj, new_par, pos, { 'core' : true, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id) })) {
+				this.settings.core.error.call(this, this._data.core.last_error);
+				return false;
+			}
+			node = old_ins ? old_ins.get_json(obj, { no_id : true, no_data : true, no_state : true }) : obj;
+			if(!node) { return false; }
+			if(node.id === true) { delete node.id; }
+			node = this._parse_model_from_json(node, new_par.id, new_par.parents.concat());
+			if(!node) { return false; }
+			tmp = this.get_node(node);
+			if(obj && obj.state && obj.state.loaded === false) { tmp.state.loaded = false; }
+			dpc = [];
+			dpc.push(node);
+			dpc = dpc.concat(tmp.children_d);
+			this.trigger('model', { "nodes" : dpc, "parent" : new_par.id });
+
+			// insert into new parent and up
+			for(i = 0, j = new_par.parents.length; i < j; i++) {
+				this._model.data[new_par.parents[i]].children_d = this._model.data[new_par.parents[i]].children_d.concat(dpc);
+			}
+			dpc = [];
+			for(i = 0, j = new_par.children.length; i < j; i++) {
+				dpc[i >= pos ? i+1 : i] = new_par.children[i];
+			}
+			dpc[pos] = tmp.id;
+			new_par.children = dpc;
+			new_par.children_d.push(tmp.id);
+			new_par.children_d = new_par.children_d.concat(tmp.children_d);
+
+			if(new_par.id === '#') {
+				this._model.force_full_redraw = true;
+			}
+			if(!this._model.force_full_redraw) {
+				this._node_changed(new_par.id);
+			}
+			if(!skip_redraw) {
+				this.redraw(new_par.id === '#');
+			}
+			if(callback) { callback.call(this, tmp, new_par, pos); }
+			/**
+			 * triggered when a node is copied
+			 * @event
+			 * @name copy_node.jstree
+			 * @param {Object} node the copied node
+			 * @param {Object} original the original node
+			 * @param {String} parent the parent's ID
+			 * @param {Number} position the position of the node among the parent's children
+			 * @param {String} old_parent the old parent of the node
+			 * @param {Number} old_position the position of the original node
+			 * @param {Boolean} is_multi do the node and new parent belong to different instances
+			 * @param {jsTree} old_instance the instance the node came from
+			 * @param {jsTree} new_instance the instance of the new parent
+			 */
+			this.trigger('copy_node', { "node" : tmp, "original" : obj, "parent" : new_par.id, "position" : pos, "old_parent" : old_par, "old_position" : old_ins && old_ins._id && old_par && old_ins._model.data[old_par] && old_ins._model.data[old_par].children ? $.inArray(obj.id, old_ins._model.data[old_par].children) : -1,'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id), 'old_instance' : old_ins, 'new_instance' : this });
+			return tmp.id;
+		},
+		/**
+		 * cut a node (a later call to `paste(obj)` would move the node)
+		 * @name cut(obj)
+		 * @param  {mixed} obj multiple objects can be passed using an array
+		 * @trigger cut.jstree
+		 */
+		cut : function (obj) {
+			if(!obj) { obj = this._data.core.selected.concat(); }
+			if(!$.isArray(obj)) { obj = [obj]; }
+			if(!obj.length) { return false; }
+			var tmp = [], o, t1, t2;
+			for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+				o = this.get_node(obj[t1]);
+				if(o && o.id && o.id !== '#') { tmp.push(o); }
+			}
+			if(!tmp.length) { return false; }
+			ccp_node = tmp;
+			ccp_inst = this;
+			ccp_mode = 'move_node';
+			/**
+			 * triggered when nodes are added to the buffer for moving
+			 * @event
+			 * @name cut.jstree
+			 * @param {Array} node
+			 */
+			this.trigger('cut', { "node" : obj });
+		},
+		/**
+		 * copy a node (a later call to `paste(obj)` would copy the node)
+		 * @name copy(obj)
+		 * @param  {mixed} obj multiple objects can be passed using an array
+		 * @trigger copy.jstre
+		 */
+		copy : function (obj) {
+			if(!obj) { obj = this._data.core.selected.concat(); }
+			if(!$.isArray(obj)) { obj = [obj]; }
+			if(!obj.length) { return false; }
+			var tmp = [], o, t1, t2;
+			for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+				o = this.get_node(obj[t1]);
+				if(o && o.id && o.id !== '#') { tmp.push(o); }
+			}
+			if(!tmp.length) { return false; }
+			ccp_node = tmp;
+			ccp_inst = this;
+			ccp_mode = 'copy_node';
+			/**
+			 * triggered when nodes are added to the buffer for copying
+			 * @event
+			 * @name copy.jstree
+			 * @param {Array} node
+			 */
+			this.trigger('copy', { "node" : obj });
+		},
+		/**
+		 * get the current buffer (any nodes that are waiting for a paste operation)
+		 * @name get_buffer()
+		 * @return {Object} an object consisting of `mode` ("copy_node" or "move_node"), `node` (an array of objects) and `inst` (the instance)
+		 */
+		get_buffer : function () {
+			return { 'mode' : ccp_mode, 'node' : ccp_node, 'inst' : ccp_inst };
+		},
+		/**
+		 * check if there is something in the buffer to paste
+		 * @name can_paste()
+		 * @return {Boolean}
+		 */
+		can_paste : function () {
+			return ccp_mode !== false && ccp_node !== false; // && ccp_inst._model.data[ccp_node];
+		},
+		/**
+		 * copy or move the previously cut or copied nodes to a new parent
+		 * @name paste(obj [, pos])
+		 * @param  {mixed} obj the new parent
+		 * @param  {mixed} pos the position to insert at (besides integer, "first" and "last" are supported), defaults to integer `0`
+		 * @trigger paste.jstree
+		 */
+		paste : function (obj, pos) {
+			obj = this.get_node(obj);
+			if(!obj || !ccp_mode || !ccp_mode.match(/^(copy_node|move_node)$/) || !ccp_node) { return false; }
+			if(this[ccp_mode](ccp_node, obj, pos)) {
+				/**
+				 * triggered when paste is invoked
+				 * @event
+				 * @name paste.jstree
+				 * @param {String} parent the ID of the receiving node
+				 * @param {Array} node the nodes in the buffer
+				 * @param {String} mode the performed operation - "copy_node" or "move_node"
+				 */
+				this.trigger('paste', { "parent" : obj.id, "node" : ccp_node, "mode" : ccp_mode });
+			}
+			ccp_node = false;
+			ccp_mode = false;
+			ccp_inst = false;
+		},
+		/**
+		 * clear the buffer of previously copied or cut nodes
+		 * @name clear_buffer()
+		 * @trigger clear_buffer.jstree
+		 */
+		clear_buffer : function () {
+			ccp_node = false;
+			ccp_mode = false;
+			ccp_inst = false;
+			/**
+			 * triggered when the copy / cut buffer is cleared
+			 * @event
+			 * @name clear_buffer.jstree
+			 */
+			this.trigger('clear_buffer');
+		},
+		/**
+		 * put a node in edit mode (input field to rename the node)
+		 * @name edit(obj [, default_text])
+		 * @param  {mixed} obj
+		 * @param  {String} default_text the text to populate the input with (if omitted the node text value is used)
+		 */
+		edit : function (obj, default_text) {
+			obj = this.get_node(obj);
+			if(!obj) { return false; }
+			if(this.settings.core.check_callback === false) {
+				this._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_07', 'reason' : 'Could not edit node because of check_callback' };
+				this.settings.core.error.call(this, this._data.core.last_error);
+				return false;
+			}
+			default_text = typeof default_text === 'string' ? default_text : obj.text;
+			this.set_text(obj, "");
+			obj = this._open_to(obj);
+
+			var rtl = this._data.core.rtl,
+				w  = this.element.width(),
+				a  = obj.children('.jstree-anchor'),
+				s  = $('<span>'),
+				/*!
+				oi = obj.children("i:visible"),
+				ai = a.children("i:visible"),
+				w1 = oi.width() * oi.length,
+				w2 = ai.width() * ai.length,
+				*/
+				t  = default_text,
+				h1 = $("<"+"div />", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo("body"),
+				h2 = $("<"+"input />", {
+						"value" : t,
+						"class" : "jstree-rename-input",
+						// "size" : t.length,
+						"css" : {
+							"padding" : "0",
+							"border" : "1px solid silver",
+							"box-sizing" : "border-box",
+							"display" : "inline-block",
+							"height" : (this._data.core.li_height) + "px",
+							"lineHeight" : (this._data.core.li_height) + "px",
+							"width" : "150px" // will be set a bit further down
+						},
+						"blur" : $.proxy(function () {
+							var i = s.children(".jstree-rename-input"),
+								v = i.val();
+							if(v === "") { v = t; }
+							h1.remove();
+							s.replaceWith(a);
+							s.remove();
+							this.set_text(obj, t);
+							if(this.rename_node(obj, $('<div></div>').text(v)[this.settings.core.force_text ? 'text' : 'html']()) === false) {
+								this.set_text(obj, t); // move this up? and fix #483
+							}
+						}, this),
+						"keydown" : function (event) {
+							var key = event.which;
+							if(key === 27) {
+								this.value = t;
+							}
+							if(key === 27 || key === 13 || key === 37 || key === 38 || key === 39 || key === 40 || key === 32) {
+								event.stopImmediatePropagation();
+							}
+							if(key === 27 || key === 13) {
+								event.preventDefault();
+								this.blur();
+							}
+						},
+						"click" : function (e) { e.stopImmediatePropagation(); },
+						"mousedown" : function (e) { e.stopImmediatePropagation(); },
+						"keyup" : function (event) {
+							h2.width(Math.min(h1.text("pW" + this.value).width(),w));
+						},
+						"keypress" : function(event) {
+							if(event.which === 13) { return false; }
+						}
+					}),
+				fn = {
+						fontFamily		: a.css('fontFamily')		|| '',
+						fontSize		: a.css('fontSize')			|| '',
+						fontWeight		: a.css('fontWeight')		|| '',
+						fontStyle		: a.css('fontStyle')		|| '',
+						fontStretch		: a.css('fontStretch')		|| '',
+						fontVariant		: a.css('fontVariant')		|| '',
+						letterSpacing	: a.css('letterSpacing')	|| '',
+						wordSpacing		: a.css('wordSpacing')		|| ''
+				};
+			s.attr('class', a.attr('class')).append(a.contents().clone()).append(h2);
+			a.replaceWith(s);
+			h1.css(fn);
+			h2.css(fn).width(Math.min(h1.text("pW" + h2[0].value).width(),w))[0].select();
+		},
+
+
+		/**
+		 * changes the theme
+		 * @name set_theme(theme_name [, theme_url])
+		 * @param {String} theme_name the name of the new theme to apply
+		 * @param {mixed} theme_url  the location of the CSS file for this theme. Omit or set to `false` if you manually included the file. Set to `true` to autoload from the `core.themes.dir` directory.
+		 * @trigger set_theme.jstree
+		 */
+		set_theme : function (theme_name, theme_url) {
+			if(!theme_name) { return false; }
+			if(theme_url === true) {
+				var dir = this.settings.core.themes.dir;
+				if(!dir) { dir = $.jstree.path + '/themes'; }
+				theme_url = dir + '/' + theme_name + '/style.css';
+			}
+			if(theme_url && $.inArray(theme_url, themes_loaded) === -1) {
+				$('head').append('<'+'link rel="stylesheet" href="' + theme_url + '" type="text/css" />');
+				themes_loaded.push(theme_url);
+			}
+			if(this._data.core.themes.name) {
+				this.element.removeClass('jstree-' + this._data.core.themes.name);
+			}
+			this._data.core.themes.name = theme_name;
+			this.element.addClass('jstree-' + theme_name);
+			this.element[this.settings.core.themes.responsive ? 'addClass' : 'removeClass' ]('jstree-' + theme_name + '-responsive');
+			/**
+			 * triggered when a theme is set
+			 * @event
+			 * @name set_theme.jstree
+			 * @param {String} theme the new theme
+			 */
+			this.trigger('set_theme', { 'theme' : theme_name });
+		},
+		/**
+		 * gets the name of the currently applied theme name
+		 * @name get_theme()
+		 * @return {String}
+		 */
+		get_theme : function () { return this._data.core.themes.name; },
+		/**
+		 * changes the theme variant (if the theme has variants)
+		 * @name set_theme_variant(variant_name)
+		 * @param {String|Boolean} variant_name the variant to apply (if `false` is used the current variant is removed)
+		 */
+		set_theme_variant : function (variant_name) {
+			if(this._data.core.themes.variant) {
+				this.element.removeClass('jstree-' + this._data.core.themes.name + '-' + this._data.core.themes.variant);
+			}
+			this._data.core.themes.variant = variant_name;
+			if(variant_name) {
+				this.element.addClass('jstree-' + this._data.core.themes.name + '-' + this._data.core.themes.variant);
+			}
+		},
+		/**
+		 * gets the name of the currently applied theme variant
+		 * @name get_theme()
+		 * @return {String}
+		 */
+		get_theme_variant : function () { return this._data.core.themes.variant; },
+		/**
+		 * shows a striped background on the container (if the theme supports it)
+		 * @name show_stripes()
+		 */
+		show_stripes : function () { this._data.core.themes.stripes = true; this.get_container_ul().addClass("jstree-striped"); },
+		/**
+		 * hides the striped background on the container
+		 * @name hide_stripes()
+		 */
+		hide_stripes : function () { this._data.core.themes.stripes = false; this.get_container_ul().removeClass("jstree-striped"); },
+		/**
+		 * toggles the striped background on the container
+		 * @name toggle_stripes()
+		 */
+		toggle_stripes : function () { if(this._data.core.themes.stripes) { this.hide_stripes(); } else { this.show_stripes(); } },
+		/**
+		 * shows the connecting dots (if the theme supports it)
+		 * @name show_dots()
+		 */
+		show_dots : function () { this._data.core.themes.dots = true; this.get_container_ul().removeClass("jstree-no-dots"); },
+		/**
+		 * hides the connecting dots
+		 * @name hide_dots()
+		 */
+		hide_dots : function () { this._data.core.themes.dots = false; this.get_container_ul().addClass("jstree-no-dots"); },
+		/**
+		 * toggles the connecting dots
+		 * @name toggle_dots()
+		 */
+		toggle_dots : function () { if(this._data.core.themes.dots) { this.hide_dots(); } else { this.show_dots(); } },
+		/**
+		 * show the node icons
+		 * @name show_icons()
+		 */
+		show_icons : function () { this._data.core.themes.icons = true; this.get_container_ul().removeClass("jstree-no-icons"); },
+		/**
+		 * hide the node icons
+		 * @name hide_icons()
+		 */
+		hide_icons : function () { this._data.core.themes.icons = false; this.get_container_ul().addClass("jstree-no-icons"); },
+		/**
+		 * toggle the node icons
+		 * @name toggle_icons()
+		 */
+		toggle_icons : function () { if(this._data.core.themes.icons) { this.hide_icons(); } else { this.show_icons(); } },
+		/**
+		 * set the node icon for a node
+		 * @name set_icon(obj, icon)
+		 * @param {mixed} obj
+		 * @param {String} icon the new icon - can be a path to an icon or a className, if using an image that is in the current directory use a `./` prefix, otherwise it will be detected as a class
+		 */
+		set_icon : function (obj, icon) {
+			var t1, t2, dom, old;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.set_icon(obj[t1], icon);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') { return false; }
+			old = obj.icon;
+			obj.icon = icon;
+			dom = this.get_node(obj, true).children(".jstree-anchor").children(".jstree-themeicon");
+			if(icon === false) {
+				this.hide_icon(obj);
+			}
+			else if(icon === true) {
+				dom.removeClass('jstree-themeicon-custom ' + old).css("background","").removeAttr("rel");
+				if(old === false) { this.show_icon(obj); }
+			}
+			else if(icon.indexOf("/") === -1 && icon.indexOf(".") === -1) {
+				dom.removeClass(old).css("background","");
+				dom.addClass(icon + ' jstree-themeicon-custom').attr("rel",icon);
+				if(old === false) { this.show_icon(obj); }
+			}
+			else {
+				dom.removeClass(old).css("background","");
+				dom.addClass('jstree-themeicon-custom').css("background", "url('" + icon + "') center center no-repeat").attr("rel",icon);
+				if(old === false) { this.show_icon(obj); }
+			}
+			return true;
+		},
+		/**
+		 * get the node icon for a node
+		 * @name get_icon(obj)
+		 * @param {mixed} obj
+		 * @return {String}
+		 */
+		get_icon : function (obj) {
+			obj = this.get_node(obj);
+			return (!obj || obj.id === '#') ? false : obj.icon;
+		},
+		/**
+		 * hide the icon on an individual node
+		 * @name hide_icon(obj)
+		 * @param {mixed} obj
+		 */
+		hide_icon : function (obj) {
+			var t1, t2;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.hide_icon(obj[t1]);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj === '#') { return false; }
+			obj.icon = false;
+			this.get_node(obj, true).children(".jstree-anchor").children(".jstree-themeicon").addClass('jstree-themeicon-hidden');
+			return true;
+		},
+		/**
+		 * show the icon on an individual node
+		 * @name show_icon(obj)
+		 * @param {mixed} obj
+		 */
+		show_icon : function (obj) {
+			var t1, t2, dom;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.show_icon(obj[t1]);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj === '#') { return false; }
+			dom = this.get_node(obj, true);
+			obj.icon = dom.length ? dom.children(".jstree-anchor").children(".jstree-themeicon").attr('rel') : true;
+			if(!obj.icon) { obj.icon = true; }
+			dom.children(".jstree-anchor").children(".jstree-themeicon").removeClass('jstree-themeicon-hidden');
+			return true;
+		}
+	};
+
+	// helpers
+	$.vakata = {};
+	// collect attributes
+	$.vakata.attributes = function(node, with_values) {
+		node = $(node)[0];
+		var attr = with_values ? {} : [];
+		if(node && node.attributes) {
+			$.each(node.attributes, function (i, v) {
+				if($.inArray(v.name.toLowerCase(),['style','contenteditable','hasfocus','tabindex']) !== -1) { return; }
+				if(v.value !== null && $.trim(v.value) !== '') {
+					if(with_values) { attr[v.name] = v.value; }
+					else { attr.push(v.name); }
+				}
+			});
+		}
+		return attr;
+	};
+	$.vakata.array_unique = function(array) {
+		var a = [], i, j, l;
+		for(i = 0, l = array.length; i < l; i++) {
+			for(j = 0; j <= i; j++) {
+				if(array[i] === array[j]) {
+					break;
+				}
+			}
+			if(j === i) { a.push(array[i]); }
+		}
+		return a;
+	};
+	// remove item from array
+	$.vakata.array_remove = function(array, from, to) {
+		var rest = array.slice((to || from) + 1 || array.length);
+		array.length = from < 0 ? array.length + from : from;
+		array.push.apply(array, rest);
+		return array;
+	};
+	// remove item from array
+	$.vakata.array_remove_item = function(array, item) {
+		var tmp = $.inArray(item, array);
+		return tmp !== -1 ? $.vakata.array_remove(array, tmp) : array;
+	};
+
+
+/**
+ * ### Checkbox plugin
+ *
+ * This plugin renders checkbox icons in front of each node, making multiple selection much easier. 
+ * It also supports tri-state behavior, meaning that if a node has a few of its children checked it will be rendered as undetermined, and state will be propagated up.
+ */
+
+	var _i = document.createElement('I');
+	_i.className = 'jstree-icon jstree-checkbox';
+	_i.setAttribute('role', 'presentation');
+	/**
+	 * stores all defaults for the checkbox plugin
+	 * @name $.jstree.defaults.checkbox
+	 * @plugin checkbox
+	 */
+	$.jstree.defaults.checkbox = {
+		/**
+		 * a boolean indicating if checkboxes should be visible (can be changed at a later time using `show_checkboxes()` and `hide_checkboxes`). Defaults to `true`.
+		 * @name $.jstree.defaults.checkbox.visible
+		 * @plugin checkbox
+		 */
+		visible				: true,
+		/**
+		 * a boolean indicating if checkboxes should cascade down and have an undetermined state. Defaults to `true`.
+		 * @name $.jstree.defaults.checkbox.three_state
+		 * @plugin checkbox
+		 */
+		three_state			: true,
+		/**
+		 * a boolean indicating if clicking anywhere on the node should act as clicking on the checkbox. Defaults to `true`.
+		 * @name $.jstree.defaults.checkbox.whole_node
+		 * @plugin checkbox
+		 */
+		whole_node			: true,
+		/**
+		 * a boolean indicating if the selected style of a node should be kept, or removed. Defaults to `true`.
+		 * @name $.jstree.defaults.checkbox.keep_selected_style
+		 * @plugin checkbox
+		 */
+		keep_selected_style	: true,
+		/**
+		 * This setting controls how cascading and undetermined nodes are applied. 
+		 * If 'up' is in the string - cascading up is enabled, if 'down' is in the string - cascading down is enabled, if 'undetermined' is in the string - undetermined nodes will be used. 
+		 * If `three_state` is set to `true` this setting is automatically set to 'up+down+undetermined'. Defaults to ''.
+		 * @name $.jstree.defaults.checkbox.cascade
+		 * @plugin checkbox
+		 */
+		cascade				: '',
+		/**
+		 * This setting controls if checkbox are bound to the general tree selection or to an internal array maintained by the checkbox plugin. Defaults to `true`, only set to `false` if you know exactly what you are doing. 
+		 * @name $.jstree.defaults.checkbox.tie_selection
+		 * @plugin checkbox
+		 */
+		tie_selection		: true
+	};
+	$.jstree.plugins.checkbox = function (options, parent) {
+		this.bind = function () {
+			parent.bind.call(this);
+			this._data.checkbox.uto = false;
+			this._data.checkbox.selected = [];
+			if(this.settings.checkbox.three_state) {
+				this.settings.checkbox.cascade = 'up+down+undetermined';
+			}
+			this.element
+				.on("init.jstree", $.proxy(function () {
+						this._data.checkbox.visible = this.settings.checkbox.visible;
+						if(!this.settings.checkbox.keep_selected_style) {
+							this.element.addClass('jstree-checkbox-no-clicked');
+						}
+						if(this.settings.checkbox.tie_selection) {
+							this.element.addClass('jstree-checkbox-selection');
+						}
+					}, this))
+				.on("loading.jstree", $.proxy(function () {
+						this[ this._data.checkbox.visible ? 'show_checkboxes' : 'hide_checkboxes' ]();
+					}, this));
+			if(this.settings.checkbox.cascade.indexOf('undetermined') !== -1) {
+				this.element
+					.on('changed.jstree uncheck_node.jstree check_node.jstree uncheck_all.jstree check_all.jstree move_node.jstree copy_node.jstree redraw.jstree open_node.jstree', $.proxy(function () {
+							// only if undetermined is in setting
+							if(this._data.checkbox.uto) { clearTimeout(this._data.checkbox.uto); }
+							this._data.checkbox.uto = setTimeout($.proxy(this._undetermined, this), 50);
+						}, this));
+			}
+			if(!this.settings.checkbox.tie_selection) {
+				this.element
+					.on('model.jstree', $.proxy(function (e, data) {
+						var m = this._model.data,
+							p = m[data.parent],
+							dpc = data.nodes,
+							i, j;
+						for(i = 0, j = dpc.length; i < j; i++) {
+							m[dpc[i]].state.checked = (m[dpc[i]].original && m[dpc[i]].original.state && m[dpc[i]].original.state.checked);
+							if(m[dpc[i]].state.checked) {
+								this._data.checkbox.selected.push(dpc[i]);
+							}
+						}
+					}, this));
+			}
+			if(this.settings.checkbox.cascade.indexOf('up') !== -1 || this.settings.checkbox.cascade.indexOf('down') !== -1) {
+				this.element
+					.on('model.jstree', $.proxy(function (e, data) {
+							var m = this._model.data,
+								p = m[data.parent],
+								dpc = data.nodes,
+								chd = [],
+								c, i, j, k, l, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection;
+
+							if(s.indexOf('down') !== -1) {
+								// apply down
+								if(p.state[ t ? 'selected' : 'checked' ]) {
+									for(i = 0, j = dpc.length; i < j; i++) {
+										m[dpc[i]].state[ t ? 'selected' : 'checked' ] = true;
+									}
+									this._data[ t ? 'core' : 'checkbox' ].selected = this._data[ t ? 'core' : 'checkbox' ].selected.concat(dpc);
+								}
+								else {
+									for(i = 0, j = dpc.length; i < j; i++) {
+										if(m[dpc[i]].state[ t ? 'selected' : 'checked' ]) {
+											for(k = 0, l = m[dpc[i]].children_d.length; k < l; k++) {
+												m[m[dpc[i]].children_d[k]].state[ t ? 'selected' : 'checked' ] = true;
+											}
+											this._data[ t ? 'core' : 'checkbox' ].selected = this._data[ t ? 'core' : 'checkbox' ].selected.concat(m[dpc[i]].children_d);
+										}
+									}
+								}
+							}
+
+							if(s.indexOf('up') !== -1) {
+								// apply up
+								for(i = 0, j = p.children_d.length; i < j; i++) {
+									if(!m[p.children_d[i]].children.length) {
+										chd.push(m[p.children_d[i]].parent);
+									}
+								}
+								chd = $.vakata.array_unique(chd);
+								for(k = 0, l = chd.length; k < l; k++) {
+									p = m[chd[k]];
+									while(p && p.id !== '#') {
+										c = 0;
+										for(i = 0, j = p.children.length; i < j; i++) {
+											c += m[p.children[i]].state[ t ? 'selected' : 'checked' ];
+										}
+										if(c === j) {
+											p.state[ t ? 'selected' : 'checked' ] = true;
+											this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);
+											tmp = this.get_node(p, true);
+											if(tmp && tmp.length) {
+												tmp.attr('aria-selected', true).children('.jstree-anchor').addClass( t ? 'jstree-clicked' : 'jstree-checked');
+											}
+										}
+										else {
+											break;
+										}
+										p = this.get_node(p.parent);
+									}
+								}
+							}
+
+							this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_unique(this._data[ t ? 'core' : 'checkbox' ].selected);
+						}, this))
+					.on(this.settings.checkbox.tie_selection ? 'select_node.jstree' : 'check_node.jstree', $.proxy(function (e, data) {
+							var obj = data.node,
+								m = this._model.data,
+								par = this.get_node(obj.parent),
+								dom = this.get_node(obj, true),
+								i, j, c, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection;
+
+							// apply down
+							if(s.indexOf('down') !== -1) {
+								this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_unique(this._data[ t ? 'core' : 'checkbox' ].selected.concat(obj.children_d));
+								for(i = 0, j = obj.children_d.length; i < j; i++) {
+									tmp = m[obj.children_d[i]];
+									tmp.state[ t ? 'selected' : 'checked' ] = true;
+									if(tmp && tmp.original && tmp.original.state && tmp.original.state.undetermined) {
+										tmp.original.state.undetermined = false;
+									}
+								}
+							}
+
+							// apply up
+							if(s.indexOf('up') !== -1) {
+								while(par && par.id !== '#') {
+									c = 0;
+									for(i = 0, j = par.children.length; i < j; i++) {
+										c += m[par.children[i]].state[ t ? 'selected' : 'checked' ];
+									}
+									if(c === j) {
+										par.state[ t ? 'selected' : 'checked' ] = true;
+										this._data[ t ? 'core' : 'checkbox' ].selected.push(par.id);
+										tmp = this.get_node(par, true);
+										if(tmp && tmp.length) {
+											tmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');
+										}
+									}
+									else {
+										break;
+									}
+									par = this.get_node(par.parent);
+								}
+							}
+
+							// apply down (process .children separately?)
+							if(s.indexOf('down') !== -1 && dom.length) {
+								dom.find('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked').parent().attr('aria-selected', true);
+							}
+						}, this))
+					.on(this.settings.checkbox.tie_selection ? 'deselect_all.jstree' : 'uncheck_all.jstree', $.proxy(function (e, data) {
+							var obj = this.get_node('#'),
+								m = this._model.data,
+								i, j, tmp;
+							for(i = 0, j = obj.children_d.length; i < j; i++) {
+								tmp = m[obj.children_d[i]];
+								if(tmp && tmp.original && tmp.original.state && tmp.original.state.undetermined) {
+									tmp.original.state.undetermined = false;
+								}
+							}
+						}, this))
+					.on(this.settings.checkbox.tie_selection ? 'deselect_node.jstree' : 'uncheck_node.jstree', $.proxy(function (e, data) {
+							var obj = data.node,
+								dom = this.get_node(obj, true),
+								i, j, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection;
+							if(obj && obj.original && obj.original.state && obj.original.state.undetermined) {
+								obj.original.state.undetermined = false;
+							}
+
+							// apply down
+							if(s.indexOf('down') !== -1) {
+								for(i = 0, j = obj.children_d.length; i < j; i++) {
+									tmp = this._model.data[obj.children_d[i]];
+									tmp.state[ t ? 'selected' : 'checked' ] = false;
+									if(tmp && tmp.original && tmp.original.state && tmp.original.state.undetermined) {
+										tmp.original.state.undetermined = false;
+									}
+								}
+							}
+
+							// apply up
+							if(s.indexOf('up') !== -1) {
+								for(i = 0, j = obj.parents.length; i < j; i++) {
+									tmp = this._model.data[obj.parents[i]];
+									tmp.state[ t ? 'selected' : 'checked' ] = false;
+									if(tmp && tmp.original && tmp.original.state && tmp.original.state.undetermined) {
+										tmp.original.state.undetermined = false;
+									}
+									tmp = this.get_node(obj.parents[i], true);
+									if(tmp && tmp.length) {
+										tmp.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');
+									}
+								}
+							}
+							tmp = [];
+							for(i = 0, j = this._data[ t ? 'core' : 'checkbox' ].selected.length; i < j; i++) {
+								// apply down + apply up
+								if(
+									(s.indexOf('down') === -1 || $.inArray(this._data[ t ? 'core' : 'checkbox' ].selected[i], obj.children_d) === -1) &&
+									(s.indexOf('up') === -1 || $.inArray(this._data[ t ? 'core' : 'checkbox' ].selected[i], obj.parents) === -1)
+								) {
+									tmp.push(this._data[ t ? 'core' : 'checkbox' ].selected[i]);
+								}
+							}
+							this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_unique(tmp);
+
+							// apply down (process .children separately?)
+							if(s.indexOf('down') !== -1 && dom.length) {
+								dom.find('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked').parent().attr('aria-selected', false);
+							}
+						}, this));
+			}
+			if(this.settings.checkbox.cascade.indexOf('up') !== -1) {
+				this.element
+					.on('delete_node.jstree', $.proxy(function (e, data) {
+							// apply up (whole handler)
+							var p = this.get_node(data.parent),
+								m = this._model.data,
+								i, j, c, tmp, t = this.settings.checkbox.tie_selection;
+							while(p && p.id !== '#') {
+								c = 0;
+								for(i = 0, j = p.children.length; i < j; i++) {
+									c += m[p.children[i]].state[ t ? 'selected' : 'checked' ];
+								}
+								if(c === j) {
+									p.state[ t ? 'selected' : 'checked' ] = true;
+									this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);
+									tmp = this.get_node(p, true);
+									if(tmp && tmp.length) {
+										tmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');
+									}
+								}
+								else {
+									break;
+								}
+								p = this.get_node(p.parent);
+							}
+						}, this))
+					.on('move_node.jstree', $.proxy(function (e, data) {
+							// apply up (whole handler)
+							var is_multi = data.is_multi,
+								old_par = data.old_parent,
+								new_par = this.get_node(data.parent),
+								m = this._model.data,
+								p, c, i, j, tmp, t = this.settings.checkbox.tie_selection;
+							if(!is_multi) {
+								p = this.get_node(old_par);
+								while(p && p.id !== '#') {
+									c = 0;
+									for(i = 0, j = p.children.length; i < j; i++) {
+										c += m[p.children[i]].state[ t ? 'selected' : 'checked' ];
+									}
+									if(c === j) {
+										p.state[ t ? 'selected' : 'checked' ] = true;
+										this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);
+										tmp = this.get_node(p, true);
+										if(tmp && tmp.length) {
+											tmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');
+										}
+									}
+									else {
+										break;
+									}
+									p = this.get_node(p.parent);
+								}
+							}
+							p = new_par;
+							while(p && p.id !== '#') {
+								c = 0;
+								for(i = 0, j = p.children.length; i < j; i++) {
+									c += m[p.children[i]].state[ t ? 'selected' : 'checked' ];
+								}
+								if(c === j) {
+									if(!p.state[ t ? 'selected' : 'checked' ]) {
+										p.state[ t ? 'selected' : 'checked' ] = true;
+										this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);
+										tmp = this.get_node(p, true);
+										if(tmp && tmp.length) {
+											tmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');
+										}
+									}
+								}
+								else {
+									if(p.state[ t ? 'selected' : 'checked' ]) {
+										p.state[ t ? 'selected' : 'checked' ] = false;
+										this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_remove_item(this._data[ t ? 'core' : 'checkbox' ].selected, p.id);
+										tmp = this.get_node(p, true);
+										if(tmp && tmp.length) {
+											tmp.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');
+										}
+									}
+									else {
+										break;
+									}
+								}
+								p = this.get_node(p.parent);
+							}
+						}, this));
+			}
+		};
+		/**
+		 * set the undetermined state where and if necessary. Used internally.
+		 * @private
+		 * @name _undetermined()
+		 * @plugin checkbox
+		 */
+		this._undetermined = function () {
+			var i, j, m = this._model.data, t = this.settings.checkbox.tie_selection, s = this._data[ t ? 'core' : 'checkbox' ].selected, p = [], tt = this;
+			for(i = 0, j = s.length; i < j; i++) {
+				if(m[s[i]] && m[s[i]].parents) {
+					p = p.concat(m[s[i]].parents);
+				}
+			}
+			// attempt for server side undetermined state
+			this.element.find('.jstree-closed').not(':has(.jstree-children)')
+				.each(function () {
+					var tmp = tt.get_node(this), tmp2;
+					if(!tmp.state.loaded) {
+						if(tmp.original && tmp.original.state && tmp.original.state.undetermined && tmp.original.state.undetermined === true) {
+							p.push(tmp.id);
+							p = p.concat(tmp.parents);
+						}
+					}
+					else {
+						for(i = 0, j = tmp.children_d.length; i < j; i++) {
+							tmp2 = m[tmp.children_d[i]];
+							if(!tmp2.state.loaded && tmp2.original && tmp2.original.state && tmp2.original.state.undetermined && tmp2.original.state.undetermined === true) {
+								p.push(tmp2.id);
+								p = p.concat(tmp2.parents);
+							}
+						}
+					}
+				});
+			p = $.vakata.array_unique(p);
+			p = $.vakata.array_remove_item(p,'#');
+
+			this.element.find('.jstree-undetermined').removeClass('jstree-undetermined');
+			for(i = 0, j = p.length; i < j; i++) {
+				if(!m[p[i]].state[ t ? 'selected' : 'checked' ]) {
+					s = this.get_node(p[i], true);
+					if(s && s.length) {
+						s.children('.jstree-anchor').children('.jstree-checkbox').addClass('jstree-undetermined');
+					}
+				}
+			}
+		};
+		this.redraw_node = function(obj, deep, is_callback, force_render) {
+			obj = parent.redraw_node.apply(this, arguments);
+			if(obj) {
+				var i, j, tmp = null;
+				for(i = 0, j = obj.childNodes.length; i < j; i++) {
+					if(obj.childNodes[i] && obj.childNodes[i].className && obj.childNodes[i].className.indexOf("jstree-anchor") !== -1) {
+						tmp = obj.childNodes[i];
+						break;
+					}
+				}
+				if(tmp) {
+					if(!this.settings.checkbox.tie_selection && this._model.data[obj.id].state.checked) { tmp.className += ' jstree-checked'; }
+					tmp.insertBefore(_i.cloneNode(false), tmp.childNodes[0]);
+				}
+			}
+			if(!is_callback && this.settings.checkbox.cascade.indexOf('undetermined') !== -1) {
+				if(this._data.checkbox.uto) { clearTimeout(this._data.checkbox.uto); }
+				this._data.checkbox.uto = setTimeout($.proxy(this._undetermined, this), 50);
+			}
+			return obj;
+		};
+		/**
+		 * show the node checkbox icons
+		 * @name show_checkboxes()
+		 * @plugin checkbox
+		 */
+		this.show_checkboxes = function () { this._data.core.themes.checkboxes = true; this.get_container_ul().removeClass("jstree-no-checkboxes"); };
+		/**
+		 * hide the node checkbox icons
+		 * @name hide_checkboxes()
+		 * @plugin checkbox
+		 */
+		this.hide_checkboxes = function () { this._data.core.themes.checkboxes = false; this.get_container_ul().addClass("jstree-no-checkboxes"); };
+		/**
+		 * toggle the node icons
+		 * @name toggle_checkboxes()
+		 * @plugin checkbox
+		 */
+		this.toggle_checkboxes = function () { if(this._data.core.themes.checkboxes) { this.hide_checkboxes(); } else { this.show_checkboxes(); } };
+		/**
+		 * checks if a node is in an undetermined state
+		 * @name is_undetermined(obj)
+		 * @param  {mixed} obj
+		 * @return {Boolean}
+		 */
+		this.is_undetermined = function (obj) {
+			obj = this.get_node(obj);
+			var s = this.settings.checkbox.cascade, i, j, t = this.settings.checkbox.tie_selection, d = this._data[ t ? 'core' : 'checkbox' ].selected, m = this._model.data;
+			if(!obj || obj.state[ t ? 'selected' : 'checked' ] === true || s.indexOf('undetermined') === -1 || (s.indexOf('down') === -1 && s.indexOf('up') === -1)) {
+				return false;
+			}
+			if(!obj.state.loaded && obj.original.state.undetermined === true) {
+				return true;
+			}
+			for(i = 0, j = obj.children_d.length; i < j; i++) {
+				if($.inArray(obj.children_d[i], d) !== -1 || (!m[obj.children_d[i]].state.loaded && m[obj.children_d[i]].original.state.undetermined)) {
+					return true;
+				}
+			}
+			return false;
+		};
+
+		this.activate_node = function (obj, e) {
+			if(this.settings.checkbox.tie_selection && (this.settings.checkbox.whole_node || $(e.target).hasClass('jstree-checkbox'))) {
+				e.ctrlKey = true;
+			}
+			if(this.settings.checkbox.tie_selection || (!this.settings.checkbox.whole_node && !$(e.target).hasClass('jstree-checkbox'))) {
+				return parent.activate_node.call(this, obj, e);
+			}
+			if(this.is_disabled(obj)) {
+				return false;
+			}
+			if(this.is_checked(obj)) {
+				this.uncheck_node(obj, e);
+			}
+			else {
+				this.check_node(obj, e);
+			}
+			this.trigger('activate_node', { 'node' : this.get_node(obj) });
+		};
+
+		/**
+		 * check a node (only if tie_selection in checkbox settings is false, otherwise select_node will be called internally)
+		 * @name check_node(obj)
+		 * @param {mixed} obj an array can be used to check multiple nodes
+		 * @trigger check_node.jstree
+		 * @plugin checkbox
+		 */
+		this.check_node = function (obj, e) {
+			if(this.settings.checkbox.tie_selection) { return this.select_node(obj, false, true, e); }
+			var dom, t1, t2, th;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.check_node(obj[t1], e);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') {
+				return false;
+			}
+			dom = this.get_node(obj, true);
+			if(!obj.state.checked) {
+				obj.state.checked = true;
+				this._data.checkbox.selected.push(obj.id);
+				if(dom && dom.length) {
+					dom.children('.jstree-anchor').addClass('jstree-checked');
+				}
+				/**
+				 * triggered when an node is checked (only if tie_selection in checkbox settings is false)
+				 * @event
+				 * @name check_node.jstree
+				 * @param {Object} node
+				 * @param {Array} selected the current selection
+				 * @param {Object} event the event (if any) that triggered this check_node
+				 * @plugin checkbox
+				 */
+				this.trigger('check_node', { 'node' : obj, 'selected' : this._data.checkbox.selected, 'event' : e });
+			}
+		};
+		/**
+		 * uncheck a node (only if tie_selection in checkbox settings is false, otherwise deselect_node will be called internally)
+		 * @name deselect_node(obj)
+		 * @param {mixed} obj an array can be used to deselect multiple nodes
+		 * @trigger uncheck_node.jstree
+		 * @plugin checkbox
+		 */
+		this.uncheck_node = function (obj, e) {
+			if(this.settings.checkbox.tie_selection) { return this.deselect_node(obj, false, e); }
+			var t1, t2, dom;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.uncheck_node(obj[t1], e);
+				}
+				return true;
+			}
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') {
+				return false;
+			}
+			dom = this.get_node(obj, true);
+			if(obj.state.checked) {
+				obj.state.checked = false;
+				this._data.checkbox.selected = $.vakata.array_remove_item(this._data.checkbox.selected, obj.id);
+				if(dom.length) {
+					dom.children('.jstree-anchor').removeClass('jstree-checked');
+				}
+				/**
+				 * triggered when an node is unchecked (only if tie_selection in checkbox settings is false)
+				 * @event
+				 * @name uncheck_node.jstree
+				 * @param {Object} node
+				 * @param {Array} selected the current selection
+				 * @param {Object} event the event (if any) that triggered this uncheck_node
+				 * @plugin checkbox
+				 */
+				this.trigger('uncheck_node', { 'node' : obj, 'selected' : this._data.checkbox.selected, 'event' : e });
+			}
+		};
+		/**
+		 * checks all nodes in the tree (only if tie_selection in checkbox settings is false, otherwise select_all will be called internally)
+		 * @name check_all()
+		 * @trigger check_all.jstree, changed.jstree
+		 * @plugin checkbox
+		 */
+		this.check_all = function () {
+			if(this.settings.checkbox.tie_selection) { return this.select_all(); }
+			var tmp = this._data.checkbox.selected.concat([]), i, j;
+			this._data.checkbox.selected = this._model.data['#'].children_d.concat();
+			for(i = 0, j = this._data.checkbox.selected.length; i < j; i++) {
+				if(this._model.data[this._data.checkbox.selected[i]]) {
+					this._model.data[this._data.checkbox.selected[i]].state.checked = true;
+				}
+			}
+			this.redraw(true);
+			/**
+			 * triggered when all nodes are checked (only if tie_selection in checkbox settings is false)
+			 * @event
+			 * @name check_all.jstree
+			 * @param {Array} selected the current selection
+			 * @plugin checkbox
+			 */
+			this.trigger('check_all', { 'selected' : this._data.checkbox.selected });
+		};
+		/**
+		 * uncheck all checked nodes (only if tie_selection in checkbox settings is false, otherwise deselect_all will be called internally)
+		 * @name uncheck_all()
+		 * @trigger uncheck_all.jstree
+		 * @plugin checkbox
+		 */
+		this.uncheck_all = function () {
+			if(this.settings.checkbox.tie_selection) { return this.deselect_all(); }
+			var tmp = this._data.checkbox.selected.concat([]), i, j;
+			for(i = 0, j = this._data.checkbox.selected.length; i < j; i++) {
+				if(this._model.data[this._data.checkbox.selected[i]]) {
+					this._model.data[this._data.checkbox.selected[i]].state.checked = false;
+				}
+			}
+			this._data.checkbox.selected = [];
+			this.element.find('.jstree-checked').removeClass('jstree-checked');
+			/**
+			 * triggered when all nodes are unchecked (only if tie_selection in checkbox settings is false)
+			 * @event
+			 * @name uncheck_all.jstree
+			 * @param {Object} node the previous selection
+			 * @param {Array} selected the current selection
+			 * @plugin checkbox
+			 */
+			this.trigger('uncheck_all', { 'selected' : this._data.checkbox.selected, 'node' : tmp });
+		};
+		/**
+		 * checks if a node is checked (if tie_selection is on in the settings this function will return the same as is_selected)
+		 * @name is_checked(obj)
+		 * @param  {mixed}  obj
+		 * @return {Boolean}
+		 * @plugin checkbox
+		 */
+		this.is_checked = function (obj) {
+			if(this.settings.checkbox.tie_selection) { return this.is_selected(obj); }
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') { return false; }
+			return obj.state.checked;
+		};
+		/**
+		 * get an array of all checked nodes (if tie_selection is on in the settings this function will return the same as get_selected)
+		 * @name get_checked([full])
+		 * @param  {mixed}  full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned
+		 * @return {Array}
+		 * @plugin checkbox
+		 */
+		this.get_checked = function (full) {
+			if(this.settings.checkbox.tie_selection) { return this.get_selected(full); }
+			return full ? $.map(this._data.checkbox.selected, $.proxy(function (i) { return this.get_node(i); }, this)) : this._data.checkbox.selected;
+		};
+		/**
+		 * get an array of all top level checked nodes (ignoring children of checked nodes) (if tie_selection is on in the settings this function will return the same as get_top_selected)
+		 * @name get_top_checked([full])
+		 * @param  {mixed}  full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned
+		 * @return {Array}
+		 * @plugin checkbox
+		 */
+		this.get_top_checked = function (full) {
+			if(this.settings.checkbox.tie_selection) { return this.get_top_selected(full); }
+			var tmp = this.get_checked(true),
+				obj = {}, i, j, k, l;
+			for(i = 0, j = tmp.length; i < j; i++) {
+				obj[tmp[i].id] = tmp[i];
+			}
+			for(i = 0, j = tmp.length; i < j; i++) {
+				for(k = 0, l = tmp[i].children_d.length; k < l; k++) {
+					if(obj[tmp[i].children_d[k]]) {
+						delete obj[tmp[i].children_d[k]];
+					}
+				}
+			}
+			tmp = [];
+			for(i in obj) {
+				if(obj.hasOwnProperty(i)) {
+					tmp.push(i);
+				}
+			}
+			return full ? $.map(tmp, $.proxy(function (i) { return this.get_node(i); }, this)) : tmp;
+		};
+		/**
+		 * get an array of all bottom level checked nodes (ignoring selected parents) (if tie_selection is on in the settings this function will return the same as get_bottom_selected)
+		 * @name get_bottom_checked([full])
+		 * @param  {mixed}  full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned
+		 * @return {Array}
+		 * @plugin checkbox
+		 */
+		this.get_bottom_checked = function (full) {
+			if(this.settings.checkbox.tie_selection) { return this.get_bottom_selected(full); }
+			var tmp = this.get_checked(true),
+				obj = [], i, j;
+			for(i = 0, j = tmp.length; i < j; i++) {
+				if(!tmp[i].children.length) {
+					obj.push(tmp[i].id);
+				}
+			}
+			return full ? $.map(obj, $.proxy(function (i) { return this.get_node(i); }, this)) : obj;
+		};
+		this.load_node = function (obj, callback) {
+			var k, l, i, j, c, tmp;
+			if(!$.isArray(obj) && !this.settings.checkbox.tie_selection) {
+				tmp = this.get_node(obj);
+				if(tmp && tmp.state.loaded) {
+					for(k = 0, l = tmp.children_d.length; k < l; k++) {
+						if(this._model.data[tmp.children_d[k]].state.checked) {
+							c = true;
+							this._data.checkbox.selected = $.vakata.array_remove_item(this._data.checkbox.selected, tmp.children_d[k]);
+						}
+					}
+				}
+			}
+			return parent.load_node.apply(this, arguments);
+		};
+		this.get_state = function () {
+			var state = parent.get_state.apply(this, arguments);
+			if(this.settings.checkbox.tie_selection) { return state; }
+			state.checkbox = this._data.checkbox.selected.slice();
+			return state;
+		};
+		this.set_state = function (state, callback) {
+			var res = parent.set_state.apply(this, arguments);
+			if(res && state.checkbox) {
+				if(!this.settings.checkbox.tie_selection) {
+					this.uncheck_all();
+					var _this = this;
+					$.each(state.checkbox, function (i, v) {
+						_this.check_node(v);
+					});
+				}
+				delete state.checkbox;
+				return false;
+			}
+			return res;
+		};
+	};
+
+	// include the checkbox plugin by default
+	// $.jstree.defaults.plugins.push("checkbox");
+
+/**
+ * ### Contextmenu plugin
+ *
+ * Shows a context menu when a node is right-clicked.
+ */
+
+	var cto = null, ex, ey;
+
+	/**
+	 * stores all defaults for the contextmenu plugin
+	 * @name $.jstree.defaults.contextmenu
+	 * @plugin contextmenu
+	 */
+	$.jstree.defaults.contextmenu = {
+		/**
+		 * a boolean indicating if the node should be selected when the context menu is invoked on it. Defaults to `true`.
+		 * @name $.jstree.defaults.contextmenu.select_node
+		 * @plugin contextmenu
+		 */
+		select_node : true,
+		/**
+		 * a boolean indicating if the menu should be shown aligned with the node. Defaults to `true`, otherwise the mouse coordinates are used.
+		 * @name $.jstree.defaults.contextmenu.show_at_node
+		 * @plugin contextmenu
+		 */
+		show_at_node : true,
+		/**
+		 * an object of actions, or a function that accepts a node and a callback function and calls the callback function with an object of actions available for that node (you can also return the items too).
+		 * 
+		 * Each action consists of a key (a unique name) and a value which is an object with the following properties (only label and action are required):
+		 * 
+		 * * `separator_before` - a boolean indicating if there should be a separator before this item
+		 * * `separator_after` - a boolean indicating if there should be a separator after this item
+		 * * `_disabled` - a boolean indicating if this action should be disabled
+		 * * `label` - a string - the name of the action (could be a function returning a string)
+		 * * `action` - a function to be executed if this item is chosen
+		 * * `icon` - a string, can be a path to an icon or a className, if using an image that is in the current directory use a `./` prefix, otherwise it will be detected as a class
+		 * * `shortcut` - keyCode which will trigger the action if the menu is open (for example `113` for rename, which equals F2)
+		 * * `shortcut_label` - shortcut label (like for example `F2` for rename)
+		 * 
+		 * @name $.jstree.defaults.contextmenu.items
+		 * @plugin contextmenu
+		 */
+		items : function (o, cb) { // Could be an object directly
+			return {
+				"create" : {
+					"separator_before"	: false,
+					"separator_after"	: true,
+					"_disabled"			: false, //(this.check("create_node", data.reference, {}, "last")),
+					"label"				: "Create",
+					"action"			: function (data) {
+						var inst = $.jstree.reference(data.reference),
+							obj = inst.get_node(data.reference);
+						inst.create_node(obj, {}, "last", function (new_node) {
+							setTimeout(function () { inst.edit(new_node); },0);
+						});
+					}
+				},
+				"rename" : {
+					"separator_before"	: false,
+					"separator_after"	: false,
+					"_disabled"			: false, //(this.check("rename_node", data.reference, this.get_parent(data.reference), "")),
+					"label"				: "Rename",
+					/*
+					"shortcut"			: 113,
+					"shortcut_label"	: 'F2',
+					"icon"				: "glyphicon glyphicon-leaf",
+					*/
+					"action"			: function (data) {
+						var inst = $.jstree.reference(data.reference),
+							obj = inst.get_node(data.reference);
+						inst.edit(obj);
+					}
+				},
+				"remove" : {
+					"separator_before"	: false,
+					"icon"				: false,
+					"separator_after"	: false,
+					"_disabled"			: false, //(this.check("delete_node", data.reference, this.get_parent(data.reference), "")),
+					"label"				: "Delete",
+					"action"			: function (data) {
+						var inst = $.jstree.reference(data.reference),
+							obj = inst.get_node(data.reference);
+						if(inst.is_selected(obj)) {
+							inst.delete_node(inst.get_selected());
+						}
+						else {
+							inst.delete_node(obj);
+						}
+					}
+				},
+				"ccp" : {
+					"separator_before"	: true,
+					"icon"				: false,
+					"separator_after"	: false,
+					"label"				: "Edit",
+					"action"			: false,
+					"submenu" : {
+						"cut" : {
+							"separator_before"	: false,
+							"separator_after"	: false,
+							"label"				: "Cut",
+							"action"			: function (data) {
+								var inst = $.jstree.reference(data.reference),
+									obj = inst.get_node(data.reference);
+								if(inst.is_selected(obj)) {
+									inst.cut(inst.get_selected());
+								}
+								else {
+									inst.cut(obj);
+								}
+							}
+						},
+						"copy" : {
+							"separator_before"	: false,
+							"icon"				: false,
+							"separator_after"	: false,
+							"label"				: "Copy",
+							"action"			: function (data) {
+								var inst = $.jstree.reference(data.reference),
+									obj = inst.get_node(data.reference);
+								if(inst.is_selected(obj)) {
+									inst.copy(inst.get_selected());
+								}
+								else {
+									inst.copy(obj);
+								}
+							}
+						},
+						"paste" : {
+							"separator_before"	: false,
+							"icon"				: false,
+							"_disabled"			: function (data) {
+								return !$.jstree.reference(data.reference).can_paste();
+							},
+							"separator_after"	: false,
+							"label"				: "Paste",
+							"action"			: function (data) {
+								var inst = $.jstree.reference(data.reference),
+									obj = inst.get_node(data.reference);
+								inst.paste(obj);
+							}
+						}
+					}
+				}
+			};
+		}
+	};
+
+	$.jstree.plugins.contextmenu = function (options, parent) {
+		this.bind = function () {
+			parent.bind.call(this);
+
+			var last_ts = 0;
+			this.element
+				.on("contextmenu.jstree", ".jstree-anchor", $.proxy(function (e, data) {
+						e.preventDefault();
+						last_ts = e.ctrlKey ? +new Date() : 0;
+						if(data || cto) {
+							last_ts = (+new Date()) + 10000;
+						}
+						if(cto) {
+							clearTimeout(cto);
+						}
+						if(!this.is_loading(e.currentTarget)) {
+							this.show_contextmenu(e.currentTarget, e.pageX, e.pageY, e);
+						}
+					}, this))
+				.on("click.jstree", ".jstree-anchor", $.proxy(function (e) {
+						if(this._data.contextmenu.visible && (!last_ts || (+new Date()) - last_ts > 250)) { // work around safari & macOS ctrl+click
+							$.vakata.context.hide();
+						}
+						last_ts = 0;
+					}, this))
+				.on("touchstart.jstree", ".jstree-anchor", function (e) {
+						if(!e.originalEvent || !e.originalEvent.changedTouches || !e.originalEvent.changedTouches[0]) {
+							return;
+						}
+						ex = e.pageX;
+						ey = e.pageY;
+						cto = setTimeout(function () {
+							$(e.currentTarget).trigger('contextmenu', true);
+						}, 750);
+					});
+			/*
+			if(!('oncontextmenu' in document.body) && ('ontouchstart' in document.body)) {
+				var el = null, tm = null;
+				this.element
+					.on("touchstart", ".jstree-anchor", function (e) {
+						el = e.currentTarget;
+						tm = +new Date();
+						$(document).one("touchend", function (e) {
+							e.target = document.elementFromPoint(e.originalEvent.targetTouches[0].pageX - window.pageXOffset, e.originalEvent.targetTouches[0].pageY - window.pageYOffset);
+							e.currentTarget = e.target;
+							tm = ((+(new Date())) - tm);
+							if(e.target === el && tm > 600 && tm < 1000) {
+								e.preventDefault();
+								$(el).trigger('contextmenu', e);
+							}
+							el = null;
+							tm = null;
+						});
+					});
+			}
+			*/
+			$(document).on("context_hide.vakata.jstree", $.proxy(function () { this._data.contextmenu.visible = false; }, this));
+		};
+		this.teardown = function () {
+			if(this._data.contextmenu.visible) {
+				$.vakata.context.hide();
+			}
+			parent.teardown.call(this);
+		};
+
+		/**
+		 * prepare and show the context menu for a node
+		 * @name show_contextmenu(obj [, x, y])
+		 * @param {mixed} obj the node
+		 * @param {Number} x the x-coordinate relative to the document to show the menu at
+		 * @param {Number} y the y-coordinate relative to the document to show the menu at
+		 * @param {Object} e the event if available that triggered the contextmenu
+		 * @plugin contextmenu
+		 * @trigger show_contextmenu.jstree
+		 */
+		this.show_contextmenu = function (obj, x, y, e) {
+			obj = this.get_node(obj);
+			if(!obj || obj.id === '#') { return false; }
+			var s = this.settings.contextmenu,
+				d = this.get_node(obj, true),
+				a = d.children(".jstree-anchor"),
+				o = false,
+				i = false;
+			if(s.show_at_node || x === undefined || y === undefined) {
+				o = a.offset();
+				x = o.left;
+				y = o.top + this._data.core.li_height;
+			}
+			if(this.settings.contextmenu.select_node && !this.is_selected(obj)) {
+				this.activate_node(obj, e);
+			}
+
+			i = s.items;
+			if($.isFunction(i)) {
+				i = i.call(this, obj, $.proxy(function (i) {
+					this._show_contextmenu(obj, x, y, i);
+				}, this));
+			}
+			if($.isPlainObject(i)) {
+				this._show_contextmenu(obj, x, y, i);
+			}
+		};
+		/**
+		 * show the prepared context menu for a node
+		 * @name _show_contextmenu(obj, x, y, i)
+		 * @param {mixed} obj the node
+		 * @param {Number} x the x-coordinate relative to the document to show the menu at
+		 * @param {Number} y the y-coordinate relative to the document to show the menu at
+		 * @param {Number} i the object of items to show
+		 * @plugin contextmenu
+		 * @trigger show_contextmenu.jstree
+		 * @private
+		 */
+		this._show_contextmenu = function (obj, x, y, i) {
+			var d = this.get_node(obj, true),
+				a = d.children(".jstree-anchor");
+			$(document).one("context_show.vakata.jstree", $.proxy(function (e, data) {
+				var cls = 'jstree-contextmenu jstree-' + this.get_theme() + '-contextmenu';
+				$(data.element).addClass(cls);
+			}, this));
+			this._data.contextmenu.visible = true;
+			$.vakata.context.show(a, { 'x' : x, 'y' : y }, i);
+			/**
+			 * triggered when the contextmenu is shown for a node
+			 * @event
+			 * @name show_contextmenu.jstree
+			 * @param {Object} node the node
+			 * @param {Number} x the x-coordinate of the menu relative to the document
+			 * @param {Number} y the y-coordinate of the menu relative to the document
+			 * @plugin contextmenu
+			 */
+			this.trigger('show_contextmenu', { "node" : obj, "x" : x, "y" : y });
+		};
+	};
+
+	$(function () {
+		$(document)
+			.on('touchmove.vakata.jstree', function (e) {
+				if(cto && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0] && (Math.abs(ex - e.pageX) > 50 || Math.abs(ey - e.pageY) > 50)) {
+					clearTimeout(cto);
+				}
+			})
+			.on('touchend.vakata.jstree', function (e) {
+				if(cto) {
+					clearTimeout(cto);
+				}
+			});
+	});
+
+	// contextmenu helper
+	(function ($) {
+		var right_to_left = false,
+			vakata_context = {
+				element		: false,
+				reference	: false,
+				position_x	: 0,
+				position_y	: 0,
+				items		: [],
+				html		: "",
+				is_visible	: false
+			};
+
+		$.vakata.context = {
+			settings : {
+				hide_onmouseleave	: 0,
+				icons				: true
+			},
+			_trigger : function (event_name) {
+				$(document).triggerHandler("context_" + event_name + ".vakata", {
+					"reference"	: vakata_context.reference,
+					"element"	: vakata_context.element,
+					"position"	: {
+						"x" : vakata_context.position_x,
+						"y" : vakata_context.position_y
+					}
+				});
+			},
+			_execute : function (i) {
+				i = vakata_context.items[i];
+				return i && (!i._disabled || ($.isFunction(i._disabled) && !i._disabled({ "item" : i, "reference" : vakata_context.reference, "element" : vakata_context.element }))) && i.action ? i.action.call(null, {
+							"item"		: i,
+							"reference"	: vakata_context.reference,
+							"element"	: vakata_context.element,
+							"position"	: {
+								"x" : vakata_context.position_x,
+								"y" : vakata_context.position_y
+							}
+						}) : false;
+			},
+			_parse : function (o, is_callback) {
+				if(!o) { return false; }
+				if(!is_callback) {
+					vakata_context.html		= "";
+					vakata_context.items	= [];
+				}
+				var str = "",
+					sep = false,
+					tmp;
+
+				if(is_callback) { str += "<"+"ul>"; }
+				$.each(o, function (i, val) {
+					if(!val) { return true; }
+					vakata_context.items.push(val);
+					if(!sep && val.separator_before) {
+						str += "<"+"li class='vakata-context-separator'><"+"a href='#' " + ($.vakata.context.settings.icons ? '' : 'style="margin-left:0px;"') + ">&#160;<"+"/a><"+"/li>";
+					}
+					sep = false;
+					str += "<"+"li class='" + (val._class || "") + (val._disabled === true || ($.isFunction(val._disabled) && val._disabled({ "item" : val, "reference" : vakata_context.reference, "element" : vakata_context.element })) ? " vakata-contextmenu-disabled " : "") + "' "+(val.shortcut?" data-shortcut='"+val.shortcut+"' ":'')+">";
+					str += "<"+"a href='#' rel='" + (vakata_context.items.length - 1) + "'>";
+					if($.vakata.context.settings.icons) {
+						str += "<"+"i ";
+						if(val.icon) {
+							if(val.icon.indexOf("/") !== -1 || val.icon.indexOf(".") !== -1) { str += " style='background:url(\"" + val.icon + "\") center center no-repeat' "; }
+							else { str += " class='" + val.icon + "' "; }
+						}
+						str += "><"+"/i><"+"span class='vakata-contextmenu-sep'>&#160;<"+"/span>";
+					}
+					str += ($.isFunction(val.label) ? val.label({ "item" : i, "reference" : vakata_context.reference, "element" : vakata_context.element }) : val.label) + (val.shortcut?' <span class="vakata-contextmenu-shortcut vakata-contextmenu-shortcut-'+val.shortcut+'">'+ (val.shortcut_label || '') +'</span>':'') + "<"+"/a>";
+					if(val.submenu) {
+						tmp = $.vakata.context._parse(val.submenu, true);
+						if(tmp) { str += tmp; }
+					}
+					str += "<"+"/li>";
+					if(val.separator_after) {
+						str += "<"+"li class='vakata-context-separator'><"+"a href='#' " + ($.vakata.context.settings.icons ? '' : 'style="margin-left:0px;"') + ">&#160;<"+"/a><"+"/li>";
+						sep = true;
+					}
+				});
+				str  = str.replace(/<li class\='vakata-context-separator'\><\/li\>$/,"");
+				if(is_callback) { str += "</ul>"; }
+				/**
+				 * triggered on the document when the contextmenu is parsed (HTML is built)
+				 * @event
+				 * @plugin contextmenu
+				 * @name context_parse.vakata
+				 * @param {jQuery} reference the element that was right clicked
+				 * @param {jQuery} element the DOM element of the menu itself
+				 * @param {Object} position the x & y coordinates of the menu
+				 */
+				if(!is_callback) { vakata_context.html = str; $.vakata.context._trigger("parse"); }
+				return str.length > 10 ? str : false;
+			},
+			_show_submenu : function (o) {
+				o = $(o);
+				if(!o.length || !o.children("ul").length) { return; }
+				var e = o.children("ul"),
+					x = o.offset().left + o.outerWidth(),
+					y = o.offset().top,
+					w = e.width(),
+					h = e.height(),
+					dw = $(window).width() + $(window).scrollLeft(),
+					dh = $(window).height() + $(window).scrollTop();
+				// може да се спести е една проверка - дали няма някой от класовете вече нагоре
+				if(right_to_left) {
+					o[x - (w + 10 + o.outerWidth()) < 0 ? "addClass" : "removeClass"]("vakata-context-left");
+				}
+				else {
+					o[x + w + 10 > dw ? "addClass" : "removeClass"]("vakata-context-right");
+				}
+				if(y + h + 10 > dh) {
+					e.css("bottom","-1px");
+				}
+				e.show();
+			},
+			show : function (reference, position, data) {
+				var o, e, x, y, w, h, dw, dh, cond = true;
+				if(vakata_context.element && vakata_context.element.length) {
+					vakata_context.element.width('');
+				}
+				switch(cond) {
+					case (!position && !reference):
+						return false;
+					case (!!position && !!reference):
+						vakata_context.reference	= reference;
+						vakata_context.position_x	= position.x;
+						vakata_context.position_y	= position.y;
+						break;
+					case (!position && !!reference):
+						vakata_context.reference	= reference;
+						o = reference.offset();
+						vakata_context.position_x	= o.left + reference.outerHeight();
+						vakata_context.position_y	= o.top;
+						break;
+					case (!!position && !reference):
+						vakata_context.position_x	= position.x;
+						vakata_context.position_y	= position.y;
+						break;
+				}
+				if(!!reference && !data && $(reference).data('vakata_contextmenu')) {
+					data = $(reference).data('vakata_contextmenu');
+				}
+				if($.vakata.context._parse(data)) {
+					vakata_context.element.html(vakata_context.html);
+				}
+				if(vakata_context.items.length) {
+					vakata_context.element.appendTo("body");
+					e = vakata_context.element;
+					x = vakata_context.position_x;
+					y = vakata_context.position_y;
+					w = e.width();
+					h = e.height();
+					dw = $(window).width() + $(window).scrollLeft();
+					dh = $(window).height() + $(window).scrollTop();
+					if(right_to_left) {
+						x -= (e.outerWidth() - $(reference).outerWidth());
+						if(x < $(window).scrollLeft() + 20) {
+							x = $(window).scrollLeft() + 20;
+						}
+					}
+					if(x + w + 20 > dw) {
+						x = dw - (w + 20);
+					}
+					if(y + h + 20 > dh) {
+						y = dh - (h + 20);
+					}
+
+					vakata_context.element
+						.css({ "left" : x, "top" : y })
+						.show()
+						.find('a').first().focus().parent().addClass("vakata-context-hover");
+					vakata_context.is_visible = true;
+					/**
+					 * triggered on the document when the contextmenu is shown
+					 * @event
+					 * @plugin contextmenu
+					 * @name context_show.vakata
+					 * @param {jQuery} reference the element that was right clicked
+					 * @param {jQuery} element the DOM element of the menu itself
+					 * @param {Object} position the x & y coordinates of the menu
+					 */
+					$.vakata.context._trigger("show");
+				}
+			},
+			hide : function () {
+				if(vakata_context.is_visible) {
+					vakata_context.element.hide().find("ul").hide().end().find(':focus').blur().end().detach();
+					vakata_context.is_visible = false;
+					/**
+					 * triggered on the document when the contextmenu is hidden
+					 * @event
+					 * @plugin contextmenu
+					 * @name context_hide.vakata
+					 * @param {jQuery} reference the element that was right clicked
+					 * @param {jQuery} element the DOM element of the menu itself
+					 * @param {Object} position the x & y coordinates of the menu
+					 */
+					$.vakata.context._trigger("hide");
+				}
+			}
+		};
+		$(function () {
+			right_to_left = $("body").css("direction") === "rtl";
+			var to = false;
+
+			vakata_context.element = $("<ul class='vakata-context'></ul>");
+			vakata_context.element
+				.on("mouseenter", "li", function (e) {
+					e.stopImmediatePropagation();
+
+					if($.contains(this, e.relatedTarget)) {
+						// премахнато заради delegate mouseleave по-долу
+						// $(this).find(".vakata-context-hover").removeClass("vakata-context-hover");
+						return;
+					}
+
+					if(to) { clearTimeout(to); }
+					vakata_context.element.find(".vakata-context-hover").removeClass("vakata-context-hover").end();
+
+					$(this)
+						.siblings().find("ul").hide().end().end()
+						.parentsUntil(".vakata-context", "li").addBack().addClass("vakata-context-hover");
+					$.vakata.context._show_submenu(this);
+				})
+				// тестово - дали не натоварва?
+				.on("mouseleave", "li", function (e) {
+					if($.contains(this, e.relatedTarget)) { return; }
+					$(this).find(".vakata-context-hover").addBack().removeClass("vakata-context-hover");
+				})
+				.on("mouseleave", function (e) {
+					$(this).find(".vakata-context-hover").removeClass("vakata-context-hover");
+					if($.vakata.context.settings.hide_onmouseleave) {
+						to = setTimeout(
+							(function (t) {
+								return function () { $.vakata.context.hide(); };
+							}(this)), $.vakata.context.settings.hide_onmouseleave);
+					}
+				})
+				.on("click", "a", function (e) {
+					e.preventDefault();
+				//})
+				//.on("mouseup", "a", function (e) {
+					if(!$(this).blur().parent().hasClass("vakata-context-disabled") && $.vakata.context._execute($(this).attr("rel")) !== false) {
+						$.vakata.context.hide();
+					}
+				})
+				.on('keydown', 'a', function (e) {
+						var o = null;
+						switch(e.which) {
+							case 13:
+							case 32:
+								e.type = "mouseup";
+								e.preventDefault();
+								$(e.currentTarget).trigger(e);
+								break;
+							case 37:
+								if(vakata_context.is_visible) {
+									vakata_context.element.find(".vakata-context-hover").last().closest("li").first().find("ul").hide().find(".vakata-context-hover").removeClass("vakata-context-hover").end().end().children('a').focus();
+									e.stopImmediatePropagation();
+									e.preventDefault();
+								}
+								break;
+							case 38:
+								if(vakata_context.is_visible) {
+									o = vakata_context.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").prevAll("li:not(.vakata-context-separator)").first();
+									if(!o.length) { o = vakata_context.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").last(); }
+									o.addClass("vakata-context-hover").children('a').focus();
+									e.stopImmediatePropagation();
+									e.preventDefault();
+								}
+								break;
+							case 39:
+								if(vakata_context.is_visible) {
+									vakata_context.element.find(".vakata-context-hover").last().children("ul").show().children("li:not(.vakata-context-separator)").removeClass("vakata-context-hover").first().addClass("vakata-context-hover").children('a').focus();
+									e.stopImmediatePropagation();
+									e.preventDefault();
+								}
+								break;
+							case 40:
+								if(vakata_context.is_visible) {
+									o = vakata_context.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").nextAll("li:not(.vakata-context-separator)").first();
+									if(!o.length) { o = vakata_context.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").first(); }
+									o.addClass("vakata-context-hover").children('a').focus();
+									e.stopImmediatePropagation();
+									e.preventDefault();
+								}
+								break;
+							case 27:
+								$.vakata.context.hide();
+								e.preventDefault();
+								break;
+							default:
+								//console.log(e.which);
+								break;
+						}
+					})
+				.on('keydown', function (e) {
+					e.preventDefault();
+					var a = vakata_context.element.find('.vakata-contextmenu-shortcut-' + e.which).parent();
+					if(a.parent().not('.vakata-context-disabled')) {
+						a.click();
+					}
+				});
+
+			$(document)
+				.on("mousedown.vakata.jstree", function (e) {
+					if(vakata_context.is_visible && !$.contains(vakata_context.element[0], e.target)) {
+						$.vakata.context.hide();
+					}
+				})
+				.on("context_show.vakata.jstree", function (e, data) {
+					vakata_context.element.find("li:has(ul)").children("a").addClass("vakata-context-parent");
+					if(right_to_left) {
+						vakata_context.element.addClass("vakata-context-rtl").css("direction", "rtl");
+					}
+					// also apply a RTL class?
+					vakata_context.element.find("ul").hide().end();
+				});
+		});
+	}($));
+	// $.jstree.defaults.plugins.push("contextmenu");
+
+/**
+ * ### Drag'n'drop plugin
+ *
+ * Enables dragging and dropping of nodes in the tree, resulting in a move or copy operations.
+ */
+
+	/**
+	 * stores all defaults for the drag'n'drop plugin
+	 * @name $.jstree.defaults.dnd
+	 * @plugin dnd
+	 */
+	$.jstree.defaults.dnd = {
+		/**
+		 * a boolean indicating if a copy should be possible while dragging (by pressint the meta key or Ctrl). Defaults to `true`.
+		 * @name $.jstree.defaults.dnd.copy
+		 * @plugin dnd
+		 */
+		copy : true,
+		/**
+		 * a number indicating how long a node should remain hovered while dragging to be opened. Defaults to `500`.
+		 * @name $.jstree.defaults.dnd.open_timeout
+		 * @plugin dnd
+		 */
+		open_timeout : 500,
+		/**
+		 * a function invoked each time a node is about to be dragged, invoked in the tree's scope and receives the nodes about to be dragged as an argument (array) - return `false` to prevent dragging
+		 * @name $.jstree.defaults.dnd.is_draggable
+		 * @plugin dnd
+		 */
+		is_draggable : true,
+		/**
+		 * a boolean indicating if checks should constantly be made while the user is dragging the node (as opposed to checking only on drop), default is `true`
+		 * @name $.jstree.defaults.dnd.check_while_dragging
+		 * @plugin dnd
+		 */
+		check_while_dragging : true,
+		/**
+		 * a boolean indicating if nodes from this tree should only be copied with dnd (as opposed to moved), default is `false`
+		 * @name $.jstree.defaults.dnd.always_copy
+		 * @plugin dnd
+		 */
+		always_copy : false,
+		/**
+		 * when dropping a node "inside", this setting indicates the position the node should go to - it can be an integer or a string: "first" (same as 0) or "last", default is `0`
+		 * @name $.jstree.defaults.dnd.inside_pos
+		 * @plugin dnd
+		 */
+		inside_pos : 0,
+		/**
+		 * when starting the drag on a node that is selected this setting controls if all selected nodes are dragged or only the single node, default is `true`, which means all selected nodes are dragged when the drag is started on a selected node
+		 * @name $.jstree.defaults.dnd.drag_selection
+		 * @plugin dnd
+		 */
+		drag_selection : true,
+		/**
+		 * controls whether dnd works on touch devices. If left as boolean true dnd will work the same as in desktop browsers, which in some cases may impair scrolling. If set to boolean false dnd will not work on touch devices. There is a special third option - string "selected" which means only selected nodes can be dragged on touch devices.
+		 * @name $.jstree.defaults.dnd.touch
+		 * @plugin dnd
+		 */
+		touch : true
+	};
+	// TODO: now check works by checking for each node individually, how about max_children, unique, etc?
+	$.jstree.plugins.dnd = function (options, parent) {
+		this.bind = function () {
+			parent.bind.call(this);
+
+			this.element
+				.on('mousedown.jstree touchstart.jstree', '.jstree-anchor', $.proxy(function (e) {
+					if(e.type === "touchstart" && (!this.settings.dnd.touch || (this.settings.dnd.touch === 'selected' && !$(e.currentTarget).hasClass('jstree-clicked')))) {
+						return true;
+					}
+					var obj = this.get_node(e.target),
+						mlt = this.is_selected(obj) && this.settings.drag_selection ? this.get_selected().length : 1,
+						txt = (mlt > 1 ? mlt + ' ' + this.get_string('nodes') : this.get_text(e.currentTarget));
+					if(this.settings.core.force_text) {
+						txt = $('<div />').text(txt).html();
+					}
+					if(obj && obj.id && obj.id !== "#" && (e.which === 1 || e.type === "touchstart") &&
+						(this.settings.dnd.is_draggable === true || ($.isFunction(this.settings.dnd.is_draggable) && this.settings.dnd.is_draggable.call(this, (mlt > 1 ? this.get_selected(true) : [obj]))))
+					) {
+						this.element.trigger('mousedown.jstree');
+						return $.vakata.dnd.start(e, { 'jstree' : true, 'origin' : this, 'obj' : this.get_node(obj,true), 'nodes' : mlt > 1 ? this.get_selected() : [obj.id] }, '<div id="jstree-dnd" class="jstree-' + this.get_theme() + ' jstree-' + this.get_theme() + '-' + this.get_theme_variant() + ' ' + ( this.settings.core.themes.responsive ? ' jstree-dnd-responsive' : '' ) + '"><i class="jstree-icon jstree-er"></i>' + txt + '<ins class="jstree-copy" style="display:none;">+</ins></div>');
+					}
+				}, this));
+		};
+	};
+
+	$(function() {
+		// bind only once for all instances
+		var lastmv = false,
+			laster = false,
+			opento = false,
+			marker = $('<div id="jstree-marker">&#160;</div>').hide(); //.appendTo('body');
+
+		$(document)
+			.on('dnd_start.vakata.jstree', function (e, data) {
+				lastmv = false;
+				if(!data || !data.data || !data.data.jstree) { return; }
+				marker.appendTo('body'); //.show();
+			})
+			.on('dnd_move.vakata.jstree', function (e, data) {
+				if(opento) { clearTimeout(opento); }
+				if(!data || !data.data || !data.data.jstree) { return; }
+
+				// if we are hovering the marker image do nothing (can happen on "inside" drags)
+				if(data.event.target.id && data.event.target.id === 'jstree-marker') {
+					return;
+				}
+
+				var ins = $.jstree.reference(data.event.target),
+					ref = false,
+					off = false,
+					rel = false,
+					l, t, h, p, i, o, ok, t1, t2, op, ps, pr, ip, tm;
+				// if we are over an instance
+				if(ins && ins._data && ins._data.dnd) {
+					marker.attr('class', 'jstree-' + ins.get_theme() + ( ins.settings.core.themes.responsive ? ' jstree-dnd-responsive' : '' ));
+					data.helper
+						.children().attr('class', 'jstree-' + ins.get_theme() + ' jstree-' + ins.get_theme() + '-' + ins.get_theme_variant() + ' ' + ( ins.settings.core.themes.responsive ? ' jstree-dnd-responsive' : '' ))
+						.find('.jstree-copy').first()[ data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey))) ? 'show' : 'hide' ]();
+
+
+					// if are hovering the container itself add a new root node
+					if( (data.event.target === ins.element[0] || data.event.target === ins.get_container_ul()[0]) && ins.get_container_ul().children().length === 0) {
+						ok = true;
+						for(t1 = 0, t2 = data.data.nodes.length; t1 < t2; t1++) {
+							ok = ok && ins.check( (data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey)) ) ? "copy_node" : "move_node"), (data.data.origin && data.data.origin !== ins ? data.data.origin.get_node(data.data.nodes[t1]) : data.data.nodes[t1]), '#', 'last', { 'dnd' : true, 'ref' : ins.get_node('#'), 'pos' : 'i', 'is_multi' : (data.data.origin && data.data.origin !== ins), 'is_foreign' : (!data.data.origin) });
+							if(!ok) { break; }
+						}
+						if(ok) {
+							lastmv = { 'ins' : ins, 'par' : '#', 'pos' : 'last' };
+							marker.hide();
+							data.helper.find('.jstree-icon').first().removeClass('jstree-er').addClass('jstree-ok');
+							return;
+						}
+					}
+					else {
+						// if we are hovering a tree node
+						ref = $(data.event.target).closest('.jstree-anchor');
+						if(ref && ref.length && ref.parent().is('.jstree-closed, .jstree-open, .jstree-leaf')) {
+							off = ref.offset();
+							rel = data.event.pageY - off.top;
+							h = ref.height();
+							if(rel < h / 3) {
+								o = ['b', 'i', 'a'];
+							}
+							else if(rel > h - h / 3) {
+								o = ['a', 'i', 'b'];
+							}
+							else {
+								o = rel > h / 2 ? ['i', 'a', 'b'] : ['i', 'b', 'a'];
+							}
+							$.each(o, function (j, v) {
+								switch(v) {
+									case 'b':
+										l = off.left - 6;
+										t = off.top;
+										p = ins.get_parent(ref);
+										i = ref.parent().index();
+										break;
+									case 'i':
+										ip = ins.settings.dnd.inside_pos;
+										tm = ins.get_node(ref.parent());
+										l = off.left - 2;
+										t = off.top + h / 2 + 1;
+										p = tm.id;
+										i = ip === 'first' ? 0 : (ip === 'last' ? tm.children.length : Math.min(ip, tm.children.length));
+										break;
+									case 'a':
+										l = off.left - 6;
+										t = off.top + h;
+										p = ins.get_parent(ref);
+										i = ref.parent().index() + 1;
+										break;
+								}
+								ok = true;
+								for(t1 = 0, t2 = data.data.nodes.length; t1 < t2; t1++) {
+									op = data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey))) ? "copy_node" : "move_node";
+									ps = i;
+									if(op === "move_node" && v === 'a' && (data.data.origin && data.data.origin === ins) && p === ins.get_parent(data.data.nodes[t1])) {
+										pr = ins.get_node(p);
+										if(ps > $.inArray(data.data.nodes[t1], pr.children)) {
+											ps -= 1;
+										}
+									}
+									ok = ok && ( (ins && ins.settings && ins.settings.dnd && ins.settings.dnd.check_while_dragging === false) || ins.check(op, (data.data.origin && data.data.origin !== ins ? data.data.origin.get_node(data.data.nodes[t1]) : data.data.nodes[t1]), p, ps, { 'dnd' : true, 'ref' : ins.get_node(ref.parent()), 'pos' : v, 'is_multi' : (data.data.origin && data.data.origin !== ins), 'is_foreign' : (!data.data.origin) }) );
+									if(!ok) {
+										if(ins && ins.last_error) { laster = ins.last_error(); }
+										break;
+									}
+								}
+								if(v === 'i' && ref.parent().is('.jstree-closed') && ins.settings.dnd.open_timeout) {
+									opento = setTimeout((function (x, z) { return function () { x.open_node(z); }; }(ins, ref)), ins.settings.dnd.open_timeout);
+								}
+								if(ok) {
+									lastmv = { 'ins' : ins, 'par' : p, 'pos' : v === 'i' && ip === 'last' && i === 0 && !ins.is_loaded(tm) ? 'last' : i };
+									marker.css({ 'left' : l + 'px', 'top' : t + 'px' }).show();
+									data.helper.find('.jstree-icon').first().removeClass('jstree-er').addClass('jstree-ok');
+									laster = {};
+									o = true;
+									return false;
+								}
+							});
+							if(o === true) { return; }
+						}
+					}
+				}
+				lastmv = false;
+				data.helper.find('.jstree-icon').removeClass('jstree-ok').addClass('jstree-er');
+				marker.hide();
+			})
+			.on('dnd_scroll.vakata.jstree', function (e, data) {
+				if(!data || !data.data || !data.data.jstree) { return; }
+				marker.hide();
+				lastmv = false;
+				data.helper.find('.jstree-icon').first().removeClass('jstree-ok').addClass('jstree-er');
+			})
+			.on('dnd_stop.vakata.jstree', function (e, data) {
+				if(opento) { clearTimeout(opento); }
+				if(!data || !data.data || !data.data.jstree) { return; }
+				marker.hide().detach();
+				var i, j, nodes = [];
+				if(lastmv) {
+					for(i = 0, j = data.data.nodes.length; i < j; i++) {
+						nodes[i] = data.data.origin ? data.data.origin.get_node(data.data.nodes[i]) : data.data.nodes[i];
+						if(data.data.origin) {
+							nodes[i].instance = data.data.origin;
+						}
+					}
+					lastmv.ins[ data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey))) ? 'copy_node' : 'move_node' ](nodes, lastmv.par, lastmv.pos);
+					for(i = 0, j = nodes.length; i < j; i++) {
+						if(nodes[i].instance) {
+							nodes[i].instance = null;
+						}
+					}
+				}
+				else {
+					i = $(data.event.target).closest('.jstree');
+					if(i.length && laster && laster.error && laster.error === 'check') {
+						i = i.jstree(true);
+						if(i) {
+							i.settings.core.error.call(this, laster);
+						}
+					}
+				}
+			})
+			.on('keyup.jstree keydown.jstree', function (e, data) {
+				data = $.vakata.dnd._get();
+				if(data && data.data && data.data.jstree) {
+					data.helper.find('.jstree-copy').first()[ data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (e.metaKey || e.ctrlKey))) ? 'show' : 'hide' ]();
+				}
+			});
+	});
+
+	// helpers
+	(function ($) {
+		// private variable
+		var vakata_dnd = {
+			element	: false,
+			target	: false,
+			is_down	: false,
+			is_drag	: false,
+			helper	: false,
+			helper_w: 0,
+			data	: false,
+			init_x	: 0,
+			init_y	: 0,
+			scroll_l: 0,
+			scroll_t: 0,
+			scroll_e: false,
+			scroll_i: false,
+			is_touch: false
+		};
+		$.vakata.dnd = {
+			settings : {
+				scroll_speed		: 10,
+				scroll_proximity	: 20,
+				helper_left			: 5,
+				helper_top			: 10,
+				threshold			: 5,
+				threshold_touch		: 50
+			},
+			_trigger : function (event_name, e) {
+				var data = $.vakata.dnd._get();
+				data.event = e;
+				$(document).triggerHandler("dnd_" + event_name + ".vakata", data);
+			},
+			_get : function () {
+				return {
+					"data"		: vakata_dnd.data,
+					"element"	: vakata_dnd.element,
+					"helper"	: vakata_dnd.helper
+				};
+			},
+			_clean : function () {
+				if(vakata_dnd.helper) { vakata_dnd.helper.remove(); }
+				if(vakata_dnd.scroll_i) { clearInterval(vakata_dnd.scroll_i); vakata_dnd.scroll_i = false; }
+				vakata_dnd = {
+					element	: false,
+					target	: false,
+					is_down	: false,
+					is_drag	: false,
+					helper	: false,
+					helper_w: 0,
+					data	: false,
+					init_x	: 0,
+					init_y	: 0,
+					scroll_l: 0,
+					scroll_t: 0,
+					scroll_e: false,
+					scroll_i: false,
+					is_touch: false
+				};
+				$(document).off("mousemove.vakata.jstree touchmove.vakata.jstree", $.vakata.dnd.drag);
+				$(document).off("mouseup.vakata.jstree touchend.vakata.jstree", $.vakata.dnd.stop);
+			},
+			_scroll : function (init_only) {
+				if(!vakata_dnd.scroll_e || (!vakata_dnd.scroll_l && !vakata_dnd.scroll_t)) {
+					if(vakata_dnd.scroll_i) { clearInterval(vakata_dnd.scroll_i); vakata_dnd.scroll_i = false; }
+					return false;
+				}
+				if(!vakata_dnd.scroll_i) {
+					vakata_dnd.scroll_i = setInterval($.vakata.dnd._scroll, 100);
+					return false;
+				}
+				if(init_only === true) { return false; }
+
+				var i = vakata_dnd.scroll_e.scrollTop(),
+					j = vakata_dnd.scroll_e.scrollLeft();
+				vakata_dnd.scroll_e.scrollTop(i + vakata_dnd.scroll_t * $.vakata.dnd.settings.scroll_speed);
+				vakata_dnd.scroll_e.scrollLeft(j + vakata_dnd.scroll_l * $.vakata.dnd.settings.scroll_speed);
+				if(i !== vakata_dnd.scroll_e.scrollTop() || j !== vakata_dnd.scroll_e.scrollLeft()) {
+					/**
+					 * triggered on the document when a drag causes an element to scroll
+					 * @event
+					 * @plugin dnd
+					 * @name dnd_scroll.vakata
+					 * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start
+					 * @param {DOM} element the DOM element being dragged
+					 * @param {jQuery} helper the helper shown next to the mouse
+					 * @param {jQuery} event the element that is scrolling
+					 */
+					$.vakata.dnd._trigger("scroll", vakata_dnd.scroll_e);
+				}
+			},
+			start : function (e, data, html) {
+				if(e.type === "touchstart" && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]) {
+					e.pageX = e.originalEvent.changedTouches[0].pageX;
+					e.pageY = e.originalEvent.changedTouches[0].pageY;
+					e.target = document.elementFromPoint(e.originalEvent.changedTouches[0].pageX - window.pageXOffset, e.originalEvent.changedTouches[0].pageY - window.pageYOffset);
+				}
+				if(vakata_dnd.is_drag) { $.vakata.dnd.stop({}); }
+				try {
+					e.currentTarget.unselectable = "on";
+					e.currentTarget.onselectstart = function() { return false; };
+					if(e.currentTarget.style) { e.currentTarget.style.MozUserSelect = "none"; }
+				} catch(ignore) { }
+				vakata_dnd.init_x	= e.pageX;
+				vakata_dnd.init_y	= e.pageY;
+				vakata_dnd.data		= data;
+				vakata_dnd.is_down	= true;
+				vakata_dnd.element	= e.currentTarget;
+				vakata_dnd.target	= e.target;
+				vakata_dnd.is_touch	= e.type === "touchstart";
+				if(html !== false) {
+					vakata_dnd.helper = $("<div id='vakata-dnd'></div>").html(html).css({
+						"display"		: "block",
+						"margin"		: "0",
+						"padding"		: "0",
+						"position"		: "absolute",
+						"top"			: "-2000px",
+						"lineHeight"	: "16px",
+						"zIndex"		: "10000"
+					});
+				}
+				$(document).on("mousemove.vakata.jstree touchmove.vakata.jstree", $.vakata.dnd.drag);
+				$(document).on("mouseup.vakata.jstree touchend.vakata.jstree", $.vakata.dnd.stop);
+				return false;
+			},
+			drag : function (e) {
+				if(e.type === "touchmove" && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]) {
+					e.pageX = e.originalEvent.changedTouches[0].pageX;
+					e.pageY = e.originalEvent.changedTouches[0].pageY;
+					e.target = document.elementFromPoint(e.originalEvent.changedTouches[0].pageX - window.pageXOffset, e.originalEvent.changedTouches[0].pageY - window.pageYOffset);
+				}
+				if(!vakata_dnd.is_down) { return; }
+				if(!vakata_dnd.is_drag) {
+					if(
+						Math.abs(e.pageX - vakata_dnd.init_x) > (vakata_dnd.is_touch ? $.vakata.dnd.settings.threshold_touch : $.vakata.dnd.settings.threshold) ||
+						Math.abs(e.pageY - vakata_dnd.init_y) > (vakata_dnd.is_touch ? $.vakata.dnd.settings.threshold_touch : $.vakata.dnd.settings.threshold)
+					) {
+						if(vakata_dnd.helper) {
+							vakata_dnd.helper.appendTo("body");
+							vakata_dnd.helper_w = vakata_dnd.helper.outerWidth();
+						}
+						vakata_dnd.is_drag = true;
+						/**
+						 * triggered on the document when a drag starts
+						 * @event
+						 * @plugin dnd
+						 * @name dnd_start.vakata
+						 * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start
+						 * @param {DOM} element the DOM element being dragged
+						 * @param {jQuery} helper the helper shown next to the mouse
+						 * @param {Object} event the event that caused the start (probably mousemove)
+						 */
+						$.vakata.dnd._trigger("start", e);
+					}
+					else { return; }
+				}
+
+				var d  = false, w  = false,
+					dh = false, wh = false,
+					dw = false, ww = false,
+					dt = false, dl = false,
+					ht = false, hl = false;
+
+				vakata_dnd.scroll_t = 0;
+				vakata_dnd.scroll_l = 0;
+				vakata_dnd.scroll_e = false;
+				$($(e.target).parentsUntil("body").addBack().get().reverse())
+					.filter(function () {
+						return	(/^auto|scroll$/).test($(this).css("overflow")) &&
+								(this.scrollHeight > this.offsetHeight || this.scrollWidth > this.offsetWidth);
+					})
+					.each(function () {
+						var t = $(this), o = t.offset();
+						if(this.scrollHeight > this.offsetHeight) {
+							if(o.top + t.height() - e.pageY < $.vakata.dnd.settings.scroll_proximity)	{ vakata_dnd.scroll_t = 1; }
+							if(e.pageY - o.top < $.vakata.dnd.settings.scroll_proximity)				{ vakata_dnd.scroll_t = -1; }
+						}
+						if(this.scrollWidth > this.offsetWidth) {
+							if(o.left + t.width() - e.pageX < $.vakata.dnd.settings.scroll_proximity)	{ vakata_dnd.scroll_l = 1; }
+							if(e.pageX - o.left < $.vakata.dnd.settings.scroll_proximity)				{ vakata_dnd.scroll_l = -1; }
+						}
+						if(vakata_dnd.scroll_t || vakata_dnd.scroll_l) {
+							vakata_dnd.scroll_e = $(this);
+							return false;
+						}
+					});
+
+				if(!vakata_dnd.scroll_e) {
+					d  = $(document); w = $(window);
+					dh = d.height(); wh = w.height();
+					dw = d.width(); ww = w.width();
+					dt = d.scrollTop(); dl = d.scrollLeft();
+					if(dh > wh && e.pageY - dt < $.vakata.dnd.settings.scroll_proximity)		{ vakata_dnd.scroll_t = -1;  }
+					if(dh > wh && wh - (e.pageY - dt) < $.vakata.dnd.settings.scroll_proximity)	{ vakata_dnd.scroll_t = 1; }
+					if(dw > ww && e.pageX - dl < $.vakata.dnd.settings.scroll_proximity)		{ vakata_dnd.scroll_l = -1; }
+					if(dw > ww && ww - (e.pageX - dl) < $.vakata.dnd.settings.scroll_proximity)	{ vakata_dnd.scroll_l = 1; }
+					if(vakata_dnd.scroll_t || vakata_dnd.scroll_l) {
+						vakata_dnd.scroll_e = d;
+					}
+				}
+				if(vakata_dnd.scroll_e) { $.vakata.dnd._scroll(true); }
+
+				if(vakata_dnd.helper) {
+					ht = parseInt(e.pageY + $.vakata.dnd.settings.helper_top, 10);
+					hl = parseInt(e.pageX + $.vakata.dnd.settings.helper_left, 10);
+					if(dh && ht + 25 > dh) { ht = dh - 50; }
+					if(dw && hl + vakata_dnd.helper_w > dw) { hl = dw - (vakata_dnd.helper_w + 2); }
+					vakata_dnd.helper.css({
+						left	: hl + "px",
+						top		: ht + "px"
+					});
+				}
+				/**
+				 * triggered on the document when a drag is in progress
+				 * @event
+				 * @plugin dnd
+				 * @name dnd_move.vakata
+				 * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start
+				 * @param {DOM} element the DOM element being dragged
+				 * @param {jQuery} helper the helper shown next to the mouse
+				 * @param {Object} event the event that caused this to trigger (most likely mousemove)
+				 */
+				$.vakata.dnd._trigger("move", e);
+				return false;
+			},
+			stop : function (e) {
+				if(e.type === "touchend" && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]) {
+					e.pageX = e.originalEvent.changedTouches[0].pageX;
+					e.pageY = e.originalEvent.changedTouches[0].pageY;
+					e.target = document.elementFromPoint(e.originalEvent.changedTouches[0].pageX - window.pageXOffset, e.originalEvent.changedTouches[0].pageY - window.pageYOffset);
+				}
+				if(vakata_dnd.is_drag) {
+					/**
+					 * triggered on the document when a drag stops (the dragged element is dropped)
+					 * @event
+					 * @plugin dnd
+					 * @name dnd_stop.vakata
+					 * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start
+					 * @param {DOM} element the DOM element being dragged
+					 * @param {jQuery} helper the helper shown next to the mouse
+					 * @param {Object} event the event that caused the stop
+					 */
+					$.vakata.dnd._trigger("stop", e);
+				}
+				else {
+					if(e.type === "touchend" && e.target === vakata_dnd.target) {
+						var to = setTimeout(function () { $(e.target).click(); }, 100);
+						$(e.target).one('click', function() { if(to) { clearTimeout(to); } });
+					}
+				}
+				$.vakata.dnd._clean();
+				return false;
+			}
+		};
+	}($));
+
+	// include the dnd plugin by default
+	// $.jstree.defaults.plugins.push("dnd");
+
+
+/**
+ * ### Search plugin
+ *
+ * Adds search functionality to jsTree.
+ */
+
+	/**
+	 * stores all defaults for the search plugin
+	 * @name $.jstree.defaults.search
+	 * @plugin search
+	 */
+	$.jstree.defaults.search = {
+		/**
+		 * a jQuery-like AJAX config, which jstree uses if a server should be queried for results. 
+		 * 
+		 * A `str` (which is the search string) parameter will be added with the request. The expected result is a JSON array with nodes that need to be opened so that matching nodes will be revealed.
+		 * Leave this setting as `false` to not query the server. You can also set this to a function, which will be invoked in the instance's scope and receive 2 parameters - the search string and the callback to call with the array of nodes to load.
+		 * @name $.jstree.defaults.search.ajax
+		 * @plugin search
+		 */
+		ajax : false,
+		/**
+		 * Indicates if the search should be fuzzy or not (should `chnd3` match `child node 3`). Default is `false`.
+		 * @name $.jstree.defaults.search.fuzzy
+		 * @plugin search
+		 */
+		fuzzy : false,
+		/**
+		 * Indicates if the search should be case sensitive. Default is `false`.
+		 * @name $.jstree.defaults.search.case_sensitive
+		 * @plugin search
+		 */
+		case_sensitive : false,
+		/**
+		 * Indicates if the tree should be filtered (by default) to show only matching nodes (keep in mind this can be a heavy on large trees in old browsers). 
+		 * This setting can be changed at runtime when calling the search method. Default is `false`.
+		 * @name $.jstree.defaults.search.show_only_matches
+		 * @plugin search
+		 */
+		show_only_matches : false,
+		/**
+		 * Indicates if all nodes opened to reveal the search result, should be closed when the search is cleared or a new search is performed. Default is `true`.
+		 * @name $.jstree.defaults.search.close_opened_onclear
+		 * @plugin search
+		 */
+		close_opened_onclear : true,
+		/**
+		 * Indicates if only leaf nodes should be included in search results. Default is `false`.
+		 * @name $.jstree.defaults.search.search_leaves_only
+		 * @plugin search
+		 */
+		search_leaves_only : false,
+		/**
+		 * If set to a function it wil be called in the instance's scope with two arguments - search string and node (where node will be every node in the structure, so use with caution).
+		 * If the function returns a truthy value the node will be considered a match (it might not be displayed if search_only_leaves is set to true and the node is not a leaf). Default is `false`.
+		 * @name $.jstree.defaults.search.search_callback
+		 * @plugin search
+		 */
+		search_callback : false
+	};
+
+	$.jstree.plugins.search = function (options, parent) {
+		this.bind = function () {
+			parent.bind.call(this);
+
+			this._data.search.str = "";
+			this._data.search.dom = $();
+			this._data.search.res = [];
+			this._data.search.opn = [];
+			this._data.search.som = false;
+
+			this.element
+				.on('before_open.jstree', $.proxy(function (e, data) {
+						var i, j, f, r = this._data.search.res, s = [], o = $();
+						if(r && r.length) {
+							this._data.search.dom = $(this.element[0].querySelectorAll('#' + $.map(r, function (v) { return "0123456789".indexOf(v[0]) !== -1 ? '\\3' + v[0] + ' ' + v.substr(1).replace($.jstree.idregex,'\\$&') : v.replace($.jstree.idregex,'\\$&'); }).join(', #')));
+							this._data.search.dom.children(".jstree-anchor").addClass('jstree-search');
+							if(this._data.search.som && this._data.search.res.length) {
+								for(i = 0, j = r.length; i < j; i++) {
+									s = s.concat(this.get_node(r[i]).parents);
+								}
+								s = $.vakata.array_remove_item($.vakata.array_unique(s),'#');
+								o = s.length ? $(this.element[0].querySelectorAll('#' + $.map(s, function (v) { return "0123456789".indexOf(v[0]) !== -1 ? '\\3' + v[0] + ' ' + v.substr(1).replace($.jstree.idregex,'\\$&') : v.replace($.jstree.idregex,'\\$&'); }).join(', #'))) : $();
+
+								this.element.find(".jstree-node").hide().filter('.jstree-last').filter(function() { return this.nextSibling; }).removeClass('jstree-last');
+								o = o.add(this._data.search.dom);
+								o.parentsUntil(".jstree").addBack().show()
+									.filter(".jstree-children").each(function () { $(this).children(".jstree-node:visible").eq(-1).addClass("jstree-last"); });
+							}
+						}
+					}, this))
+				.on("search.jstree", $.proxy(function (e, data) {
+						if(this._data.search.som) {
+							if(data.nodes.length) {
+								this.element.find(".jstree-node").hide().filter('.jstree-last').filter(function() { return this.nextSibling; }).removeClass('jstree-last');
+								data.nodes.parentsUntil(".jstree").addBack().show()
+									.filter(".jstree-children").each(function () { $(this).children(".jstree-node:visible").eq(-1).addClass("jstree-last"); });
+							}
+						}
+					}, this))
+				.on("clear_search.jstree", $.proxy(function (e, data) {
+						if(this._data.search.som && data.nodes.length) {
+							this.element.find(".jstree-node").css("display","").filter('.jstree-last').filter(function() { return this.nextSibling; }).removeClass('jstree-last');
+						}
+					}, this));
+		};
+		/**
+		 * used to search the tree nodes for a given string
+		 * @name search(str [, skip_async])
+		 * @param {String} str the search string
+		 * @param {Boolean} skip_async if set to true server will not be queried even if configured
+		 * @param {Boolean} show_only_matches if set to true only matching nodes will be shown (keep in mind this can be very slow on large trees or old browsers)
+		 * @plugin search
+		 * @trigger search.jstree
+		 */
+		this.search = function (str, skip_async, show_only_matches) {
+			if(str === false || $.trim(str.toString()) === "") {
+				return this.clear_search();
+			}
+			str = str.toString();
+			var s = this.settings.search,
+				a = s.ajax ? s.ajax : false,
+				f = null,
+				r = [],
+				p = [], i, j;
+			if(this._data.search.res.length) {
+				this.clear_search();
+			}
+			if(show_only_matches === undefined) {
+				show_only_matches = s.show_only_matches;
+			}
+			if(!skip_async && a !== false) {
+				if($.isFunction(a)) {
+					return a.call(this, str, $.proxy(function (d) {
+							if(d && d.d) { d = d.d; }
+							this._load_nodes(!$.isArray(d) ? [] : $.vakata.array_unique(d), function () {
+								this.search(str, true, show_only_matches);
+							}, true);
+						}, this));
+				}
+				else {
+					a = $.extend({}, a);
+					if(!a.data) { a.data = {}; }
+					a.data.str = str;
+					return $.ajax(a)
+						.fail($.proxy(function () {
+							this._data.core.last_error = { 'error' : 'ajax', 'plugin' : 'search', 'id' : 'search_01', 'reason' : 'Could not load search parents', 'data' : JSON.stringify(a) };
+							this.settings.core.error.call(this, this._data.core.last_error);
+						}, this))
+						.done($.proxy(function (d) {
+							if(d && d.d) { d = d.d; }
+							this._load_nodes(!$.isArray(d) ? [] : $.vakata.array_unique(d), function () {
+								this.search(str, true, show_only_matches);
+							}, true);
+						}, this));
+				}
+			}
+			this._data.search.str = str;
+			this._data.search.dom = $();
+			this._data.search.res = [];
+			this._data.search.opn = [];
+			this._data.search.som = show_only_matches;
+
+			f = new $.vakata.search(str, true, { caseSensitive : s.case_sensitive, fuzzy : s.fuzzy });
+
+			$.each(this._model.data, function (i, v) {
+				if(v.text && ( (s.search_callback && s.search_callback.call(this, str, v)) || (!s.search_callback && f.search(v.text).isMatch) ) && (!s.search_leaves_only || (v.state.loaded && v.children.length === 0)) ) {
+					r.push(i);
+					p = p.concat(v.parents);
+				}
+			});
+			if(r.length) {
+				p = $.vakata.array_unique(p);
+				this._search_open(p);
+				this._data.search.dom = $(this.element[0].querySelectorAll('#' + $.map(r, function (v) { return "0123456789".indexOf(v[0]) !== -1 ? '\\3' + v[0] + ' ' + v.substr(1).replace($.jstree.idregex,'\\$&') : v.replace($.jstree.idregex,'\\$&'); }).join(', #')));
+				this._data.search.res = r;
+				this._data.search.dom.children(".jstree-anchor").addClass('jstree-search');
+			}
+			/**
+			 * triggered after search is complete
+			 * @event
+			 * @name search.jstree
+			 * @param {jQuery} nodes a jQuery collection of matching nodes
+			 * @param {String} str the search string
+			 * @param {Array} res a collection of objects represeing the matching nodes
+			 * @plugin search
+			 */
+			this.trigger('search', { nodes : this._data.search.dom, str : str, res : this._data.search.res, show_only_matches : show_only_matches });
+		};
+		/**
+		 * used to clear the last search (removes classes and shows all nodes if filtering is on)
+		 * @name clear_search()
+		 * @plugin search
+		 * @trigger clear_search.jstree
+		 */
+		this.clear_search = function () {
+			this._data.search.dom.children(".jstree-anchor").removeClass("jstree-search");
+			if(this.settings.search.close_opened_onclear) {
+				this.close_node(this._data.search.opn, 0);
+			}
+			/**
+			 * triggered after search is complete
+			 * @event
+			 * @name clear_search.jstree
+			 * @param {jQuery} nodes a jQuery collection of matching nodes (the result from the last search)
+			 * @param {String} str the search string (the last search string)
+			 * @param {Array} res a collection of objects represeing the matching nodes (the result from the last search)
+			 * @plugin search
+			 */
+			this.trigger('clear_search', { 'nodes' : this._data.search.dom, str : this._data.search.str, res : this._data.search.res });
+			this._data.search.str = "";
+			this._data.search.res = [];
+			this._data.search.opn = [];
+			this._data.search.dom = $();
+		};
+		/**
+		 * opens nodes that need to be opened to reveal the search results. Used only internally.
+		 * @private
+		 * @name _search_open(d)
+		 * @param {Array} d an array of node IDs
+		 * @plugin search
+		 */
+		this._search_open = function (d) {
+			var t = this;
+			$.each(d.concat([]), function (i, v) {
+				if(v === "#") { return true; }
+				try { v = $('#' + v.replace($.jstree.idregex,'\\$&'), t.element); } catch(ignore) { }
+				if(v && v.length) {
+					if(t.is_closed(v)) {
+						t._data.search.opn.push(v[0].id);
+						t.open_node(v, function () { t._search_open(d); }, 0);
+					}
+				}
+			});
+		};
+	};
+
+	// helpers
+	(function ($) {
+		// from http://kiro.me/projects/fuse.html
+		$.vakata.search = function(pattern, txt, options) {
+			options = options || {};
+			if(options.fuzzy !== false) {
+				options.fuzzy = true;
+			}
+			pattern = options.caseSensitive ? pattern : pattern.toLowerCase();
+			var MATCH_LOCATION	= options.location || 0,
+				MATCH_DISTANCE	= options.distance || 100,
+				MATCH_THRESHOLD	= options.threshold || 0.6,
+				patternLen = pattern.length,
+				matchmask, pattern_alphabet, match_bitapScore, search;
+			if(patternLen > 32) {
+				options.fuzzy = false;
+			}
+			if(options.fuzzy) {
+				matchmask = 1 << (patternLen - 1);
+				pattern_alphabet = (function () {
+					var mask = {},
+						i = 0;
+					for (i = 0; i < patternLen; i++) {
+						mask[pattern.charAt(i)] = 0;
+					}
+					for (i = 0; i < patternLen; i++) {
+						mask[pattern.charAt(i)] |= 1 << (patternLen - i - 1);
+					}
+					return mask;
+				}());
+				match_bitapScore = function (e, x) {
+					var accuracy = e / patternLen,
+						proximity = Math.abs(MATCH_LOCATION - x);
+					if(!MATCH_DISTANCE) {
+						return proximity ? 1.0 : accuracy;
+					}
+					return accuracy + (proximity / MATCH_DISTANCE);
+				};
+			}
+			search = function (text) {
+				text = options.caseSensitive ? text : text.toLowerCase();
+				if(pattern === text || text.indexOf(pattern) !== -1) {
+					return {
+						isMatch: true,
+						score: 0
+					};
+				}
+				if(!options.fuzzy) {
+					return {
+						isMatch: false,
+						score: 1
+					};
+				}
+				var i, j,
+					textLen = text.length,
+					scoreThreshold = MATCH_THRESHOLD,
+					bestLoc = text.indexOf(pattern, MATCH_LOCATION),
+					binMin, binMid,
+					binMax = patternLen + textLen,
+					lastRd, start, finish, rd, charMatch,
+					score = 1,
+					locations = [];
+				if (bestLoc !== -1) {
+					scoreThreshold = Math.min(match_bitapScore(0, bestLoc), scoreThreshold);
+					bestLoc = text.lastIndexOf(pattern, MATCH_LOCATION + patternLen);
+					if (bestLoc !== -1) {
+						scoreThreshold = Math.min(match_bitapScore(0, bestLoc), scoreThreshold);
+					}
+				}
+				bestLoc = -1;
+				for (i = 0; i < patternLen; i++) {
+					binMin = 0;
+					binMid = binMax;
+					while (binMin < binMid) {
+						if (match_bitapScore(i, MATCH_LOCATION + binMid) <= scoreThreshold) {
+							binMin = binMid;
+						} else {
+							binMax = binMid;
+						}
+						binMid = Math.floor((binMax - binMin) / 2 + binMin);
+					}
+					binMax = binMid;
+					start = Math.max(1, MATCH_LOCATION - binMid + 1);
+					finish = Math.min(MATCH_LOCATION + binMid, textLen) + patternLen;
+					rd = new Array(finish + 2);
+					rd[finish + 1] = (1 << i) - 1;
+					for (j = finish; j >= start; j--) {
+						charMatch = pattern_alphabet[text.charAt(j - 1)];
+						if (i === 0) {
+							rd[j] = ((rd[j + 1] << 1) | 1) & charMatch;
+						} else {
+							rd[j] = ((rd[j + 1] << 1) | 1) & charMatch | (((lastRd[j + 1] | lastRd[j]) << 1) | 1) | lastRd[j + 1];
+						}
+						if (rd[j] & matchmask) {
+							score = match_bitapScore(i, j - 1);
+							if (score <= scoreThreshold) {
+								scoreThreshold = score;
+								bestLoc = j - 1;
+								locations.push(bestLoc);
+								if (bestLoc > MATCH_LOCATION) {
+									start = Math.max(1, 2 * MATCH_LOCATION - bestLoc);
+								} else {
+									break;
+								}
+							}
+						}
+					}
+					if (match_bitapScore(i + 1, MATCH_LOCATION) > scoreThreshold) {
+						break;
+					}
+					lastRd = rd;
+				}
+				return {
+					isMatch: bestLoc >= 0,
+					score: score
+				};
+			};
+			return txt === true ? { 'search' : search } : search(txt);
+		};
+	}($));
+
+	// include the search plugin by default
+	// $.jstree.defaults.plugins.push("search");
+
+/**
+ * ### Sort plugin
+ *
+ * Automatically sorts all siblings in the tree according to a sorting function.
+ */
+
+	/**
+	 * the settings function used to sort the nodes.
+	 * It is executed in the tree's context, accepts two nodes as arguments and should return `1` or `-1`.
+	 * @name $.jstree.defaults.sort
+	 * @plugin sort
+	 */
+	$.jstree.defaults.sort = function (a, b) {
+		//return this.get_type(a) === this.get_type(b) ? (this.get_text(a) > this.get_text(b) ? 1 : -1) : this.get_type(a) >= this.get_type(b);
+		return this.get_text(a) > this.get_text(b) ? 1 : -1;
+	};
+	$.jstree.plugins.sort = function (options, parent) {
+		this.bind = function () {
+			parent.bind.call(this);
+			this.element
+				.on("model.jstree", $.proxy(function (e, data) {
+						this.sort(data.parent, true);
+					}, this))
+				.on("rename_node.jstree create_node.jstree", $.proxy(function (e, data) {
+						this.sort(data.parent || data.node.parent, false);
+						this.redraw_node(data.parent || data.node.parent, true);
+					}, this))
+				.on("move_node.jstree copy_node.jstree", $.proxy(function (e, data) {
+						this.sort(data.parent, false);
+						this.redraw_node(data.parent, true);
+					}, this));
+		};
+		/**
+		 * used to sort a node's children
+		 * @private
+		 * @name sort(obj [, deep])
+		 * @param  {mixed} obj the node
+		 * @param {Boolean} deep if set to `true` nodes are sorted recursively.
+		 * @plugin sort
+		 * @trigger search.jstree
+		 */
+		this.sort = function (obj, deep) {
+			var i, j;
+			obj = this.get_node(obj);
+			if(obj && obj.children && obj.children.length) {
+				obj.children.sort($.proxy(this.settings.sort, this));
+				if(deep) {
+					for(i = 0, j = obj.children_d.length; i < j; i++) {
+						this.sort(obj.children_d[i], false);
+					}
+				}
+			}
+		};
+	};
+
+	// include the sort plugin by default
+	// $.jstree.defaults.plugins.push("sort");
+
+/**
+ * ### State plugin
+ *
+ * Saves the state of the tree (selected nodes, opened nodes) on the user's computer using available options (localStorage, cookies, etc)
+ */
+
+	var to = false;
+	/**
+	 * stores all defaults for the state plugin
+	 * @name $.jstree.defaults.state
+	 * @plugin state
+	 */
+	$.jstree.defaults.state = {
+		/**
+		 * A string for the key to use when saving the current tree (change if using multiple trees in your project). Defaults to `jstree`.
+		 * @name $.jstree.defaults.state.key
+		 * @plugin state
+		 */
+		key		: 'jstree',
+		/**
+		 * A space separated list of events that trigger a state save. Defaults to `changed.jstree open_node.jstree close_node.jstree`.
+		 * @name $.jstree.defaults.state.events
+		 * @plugin state
+		 */
+		events	: 'changed.jstree open_node.jstree close_node.jstree check_node.jstree uncheck_node.jstree',
+		/**
+		 * Time in milliseconds after which the state will expire. Defaults to 'false' meaning - no expire.
+		 * @name $.jstree.defaults.state.ttl
+		 * @plugin state
+		 */
+		ttl		: false,
+		/**
+		 * A function that will be executed prior to restoring state with one argument - the state object. Can be used to clear unwanted parts of the state.
+		 * @name $.jstree.defaults.state.filter
+		 * @plugin state
+		 */
+		filter	: false
+	};
+	$.jstree.plugins.state = function (options, parent) {
+		this.bind = function () {
+			parent.bind.call(this);
+			var bind = $.proxy(function () {
+				this.element.on(this.settings.state.events, $.proxy(function () {
+					if(to) { clearTimeout(to); }
+					to = setTimeout($.proxy(function () { this.save_state(); }, this), 100);
+				}, this));
+				/**
+				 * triggered when the state plugin is finished restoring the state (and immediately after ready if there is no state to restore).
+				 * @event
+				 * @name state_ready.jstree
+				 * @plugin state
+				 */
+				this.trigger('state_ready');
+			}, this);
+			this.element
+				.on("ready.jstree", $.proxy(function (e, data) {
+						this.element.one("restore_state.jstree", bind);
+						if(!this.restore_state()) { bind(); }
+					}, this));
+		};
+		/**
+		 * save the state
+		 * @name save_state()
+		 * @plugin state
+		 */
+		this.save_state = function () {
+			var st = { 'state' : this.get_state(), 'ttl' : this.settings.state.ttl, 'sec' : +(new Date()) };
+			$.vakata.storage.set(this.settings.state.key, JSON.stringify(st));
+		};
+		/**
+		 * restore the state from the user's computer
+		 * @name restore_state()
+		 * @plugin state
+		 */
+		this.restore_state = function () {
+			var k = $.vakata.storage.get(this.settings.state.key);
+			if(!!k) { try { k = JSON.parse(k); } catch(ex) { return false; } }
+			if(!!k && k.ttl && k.sec && +(new Date()) - k.sec > k.ttl) { return false; }
+			if(!!k && k.state) { k = k.state; }
+			if(!!k && $.isFunction(this.settings.state.filter)) { k = this.settings.state.filter.call(this, k); }
+			if(!!k) {
+				this.element.one("set_state.jstree", function (e, data) { data.instance.trigger('restore_state', { 'state' : $.extend(true, {}, k) }); });
+				this.set_state(k);
+				return true;
+			}
+			return false;
+		};
+		/**
+		 * clear the state on the user's computer
+		 * @name clear_state()
+		 * @plugin state
+		 */
+		this.clear_state = function () {
+			return $.vakata.storage.del(this.settings.state.key);
+		};
+	};
+
+	(function ($, undefined) {
+		$.vakata.storage = {
+			// simply specifying the functions in FF throws an error
+			set : function (key, val) { return window.localStorage.setItem(key, val); },
+			get : function (key) { return window.localStorage.getItem(key); },
+			del : function (key) { return window.localStorage.removeItem(key); }
+		};
+	}($));
+
+	// include the state plugin by default
+	// $.jstree.defaults.plugins.push("state");
+
+/**
+ * ### Types plugin
+ *
+ * Makes it possible to add predefined types for groups of nodes, which make it possible to easily control nesting rules and icon for each group.
+ */
+
+	/**
+	 * An object storing all types as key value pairs, where the key is the type name and the value is an object that could contain following keys (all optional).
+	 * 
+	 * * `max_children` the maximum number of immediate children this node type can have. Do not specify or set to `-1` for unlimited.
+	 * * `max_depth` the maximum number of nesting this node type can have. A value of `1` would mean that the node can have children, but no grandchildren. Do not specify or set to `-1` for unlimited.
+	 * * `valid_children` an array of node type strings, that nodes of this type can have as children. Do not specify or set to `-1` for no limits.
+	 * * `icon` a string - can be a path to an icon or a className, if using an image that is in the current directory use a `./` prefix, otherwise it will be detected as a class. Omit to use the default icon from your theme.
+	 *
+	 * There are two predefined types:
+	 * 
+	 * * `#` represents the root of the tree, for example `max_children` would control the maximum number of root nodes.
+	 * * `default` represents the default node - any settings here will be applied to all nodes that do not have a type specified.
+	 * 
+	 * @name $.jstree.defaults.types
+	 * @plugin types
+	 */
+	$.jstree.defaults.types = {
+		'#' : {},
+		'default' : {}
+	};
+
+	$.jstree.plugins.types = function (options, parent) {
+		this.init = function (el, options) {
+			var i, j;
+			if(options && options.types && options.types['default']) {
+				for(i in options.types) {
+					if(i !== "default" && i !== "#" && options.types.hasOwnProperty(i)) {
+						for(j in options.types['default']) {
+							if(options.types['default'].hasOwnProperty(j) && options.types[i][j] === undefined) {
+								options.types[i][j] = options.types['default'][j];
+							}
+						}
+					}
+				}
+			}
+			parent.init.call(this, el, options);
+			this._model.data['#'].type = '#';
+		};
+		this.refresh = function (skip_loading, forget_state) {
+			parent.refresh.call(this, skip_loading, forget_state);
+			this._model.data['#'].type = '#';
+		};
+		this.bind = function () {
+			this.element
+				.on('model.jstree', $.proxy(function (e, data) {
+						var m = this._model.data,
+							dpc = data.nodes,
+							t = this.settings.types,
+							i, j, c = 'default';
+						for(i = 0, j = dpc.length; i < j; i++) {
+							c = 'default';
+							if(m[dpc[i]].original && m[dpc[i]].original.type && t[m[dpc[i]].original.type]) {
+								c = m[dpc[i]].original.type;
+							}
+							if(m[dpc[i]].data && m[dpc[i]].data.jstree && m[dpc[i]].data.jstree.type && t[m[dpc[i]].data.jstree.type]) {
+								c = m[dpc[i]].data.jstree.type;
+							}
+							m[dpc[i]].type = c;
+							if(m[dpc[i]].icon === true && t[c].icon !== undefined) {
+								m[dpc[i]].icon = t[c].icon;
+							}
+						}
+						m['#'].type = '#';
+					}, this));
+			parent.bind.call(this);
+		};
+		this.get_json = function (obj, options, flat) {
+			var i, j,
+				m = this._model.data,
+				opt = options ? $.extend(true, {}, options, {no_id:false}) : {},
+				tmp = parent.get_json.call(this, obj, opt, flat);
+			if(tmp === false) { return false; }
+			if($.isArray(tmp)) {
+				for(i = 0, j = tmp.length; i < j; i++) {
+					tmp[i].type = tmp[i].id && m[tmp[i].id] && m[tmp[i].id].type ? m[tmp[i].id].type : "default";
+					if(options && options.no_id) {
+						delete tmp[i].id;
+						if(tmp[i].li_attr && tmp[i].li_attr.id) {
+							delete tmp[i].li_attr.id;
+						}
+						if(tmp[i].a_attr && tmp[i].a_attr.id) {
+							delete tmp[i].a_attr.id;
+						}
+					}
+				}
+			}
+			else {
+				tmp.type = tmp.id && m[tmp.id] && m[tmp.id].type ? m[tmp.id].type : "default";
+				if(options && options.no_id) {
+					tmp = this._delete_ids(tmp);
+				}
+			}
+			return tmp;
+		};
+		this._delete_ids = function (tmp) {
+			if($.isArray(tmp)) {
+				for(var i = 0, j = tmp.length; i < j; i++) {
+					tmp[i] = this._delete_ids(tmp[i]);
+				}
+				return tmp;
+			}
+			delete tmp.id;
+			if(tmp.li_attr && tmp.li_attr.id) {
+				delete tmp.li_attr.id;
+			}
+			if(tmp.a_attr && tmp.a_attr.id) {
+				delete tmp.a_attr.id;
+			}
+			if(tmp.children && $.isArray(tmp.children)) {
+				tmp.children = this._delete_ids(tmp.children);
+			}
+			return tmp;
+		};
+		this.check = function (chk, obj, par, pos, more) {
+			if(parent.check.call(this, chk, obj, par, pos, more) === false) { return false; }
+			obj = obj && obj.id ? obj : this.get_node(obj);
+			par = par && par.id ? par : this.get_node(par);
+			var m = obj && obj.id ? $.jstree.reference(obj.id) : null, tmp, d, i, j;
+			m = m && m._model && m._model.data ? m._model.data : null;
+			switch(chk) {
+				case "create_node":
+				case "move_node":
+				case "copy_node":
+					if(chk !== 'move_node' || $.inArray(obj.id, par.children) === -1) {
+						tmp = this.get_rules(par);
+						if(tmp.max_children !== undefined && tmp.max_children !== -1 && tmp.max_children === par.children.length) {
+							this._data.core.last_error = { 'error' : 'check', 'plugin' : 'types', 'id' : 'types_01', 'reason' : 'max_children prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };
+							return false;
+						}
+						if(tmp.valid_children !== undefined && tmp.valid_children !== -1 && $.inArray((obj.type || 'default'), tmp.valid_children) === -1) {
+							this._data.core.last_error = { 'error' : 'check', 'plugin' : 'types', 'id' : 'types_02', 'reason' : 'valid_children prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };
+							return false;
+						}
+						if(m && obj.children_d && obj.parents) {
+							d = 0;
+							for(i = 0, j = obj.children_d.length; i < j; i++) {
+								d = Math.max(d, m[obj.children_d[i]].parents.length);
+							}
+							d = d - obj.parents.length + 1;
+						}
+						if(d <= 0 || d === undefined) { d = 1; }
+						do {
+							if(tmp.max_depth !== undefined && tmp.max_depth !== -1 && tmp.max_depth < d) {
+								this._data.core.last_error = { 'error' : 'check', 'plugin' : 'types', 'id' : 'types_03', 'reason' : 'max_depth prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };
+								return false;
+							}
+							par = this.get_node(par.parent);
+							tmp = this.get_rules(par);
+							d++;
+						} while(par);
+					}
+					break;
+			}
+			return true;
+		};
+		/**
+		 * used to retrieve the type settings object for a node
+		 * @name get_rules(obj)
+		 * @param {mixed} obj the node to find the rules for
+		 * @return {Object}
+		 * @plugin types
+		 */
+		this.get_rules = function (obj) {
+			obj = this.get_node(obj);
+			if(!obj) { return false; }
+			var tmp = this.get_type(obj, true);
+			if(tmp.max_depth === undefined) { tmp.max_depth = -1; }
+			if(tmp.max_children === undefined) { tmp.max_children = -1; }
+			if(tmp.valid_children === undefined) { tmp.valid_children = -1; }
+			return tmp;
+		};
+		/**
+		 * used to retrieve the type string or settings object for a node
+		 * @name get_type(obj [, rules])
+		 * @param {mixed} obj the node to find the rules for
+		 * @param {Boolean} rules if set to `true` instead of a string the settings object will be returned
+		 * @return {String|Object}
+		 * @plugin types
+		 */
+		this.get_type = function (obj, rules) {
+			obj = this.get_node(obj);
+			return (!obj) ? false : ( rules ? $.extend({ 'type' : obj.type }, this.settings.types[obj.type]) : obj.type);
+		};
+		/**
+		 * used to change a node's type
+		 * @name set_type(obj, type)
+		 * @param {mixed} obj the node to change
+		 * @param {String} type the new type
+		 * @plugin types
+		 */
+		this.set_type = function (obj, type) {
+			var t, t1, t2, old_type, old_icon;
+			if($.isArray(obj)) {
+				obj = obj.slice();
+				for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+					this.set_type(obj[t1], type);
+				}
+				return true;
+			}
+			t = this.settings.types;
+			obj = this.get_node(obj);
+			if(!t[type] || !obj) { return false; }
+			old_type = obj.type;
+			old_icon = this.get_icon(obj);
+			obj.type = type;
+			if(old_icon === true || (t[old_type] && t[old_type].icon !== undefined && old_icon === t[old_type].icon)) {
+				this.set_icon(obj, t[type].icon !== undefined ? t[type].icon : true);
+			}
+			return true;
+		};
+	};
+	// include the types plugin by default
+	// $.jstree.defaults.plugins.push("types");
+
+/**
+ * ### Unique plugin
+ *
+ * Enforces that no nodes with the same name can coexist as siblings.
+ */
+
+	/**
+	 * stores all defaults for the unique plugin
+	 * @name $.jstree.defaults.unique
+	 * @plugin unique
+	 */
+	$.jstree.defaults.unique = {
+		/**
+		 * Indicates if the comparison should be case sensitive. Default is `false`.
+		 * @name $.jstree.defaults.unique.case_sensitive
+		 * @plugin unique
+		 */
+		case_sensitive : false,
+		/**
+		 * A callback executed in the instance's scope when a new node is created and the name is already taken, the two arguments are the conflicting name and the counter. The default will produce results like `New node (2)`.
+		 * @name $.jstree.defaults.unique.duplicate
+		 * @plugin unique
+		 */
+		duplicate : function (name, counter) {
+			return name + ' (' + counter + ')';
+		}
+	};
+
+	$.jstree.plugins.unique = function (options, parent) {
+		this.check = function (chk, obj, par, pos, more) {
+			if(parent.check.call(this, chk, obj, par, pos, more) === false) { return false; }
+			obj = obj && obj.id ? obj : this.get_node(obj);
+			par = par && par.id ? par : this.get_node(par);
+			if(!par || !par.children) { return true; }
+			var n = chk === "rename_node" ? pos : obj.text,
+				c = [],
+				s = this.settings.unique.case_sensitive,
+				m = this._model.data, i, j;
+			for(i = 0, j = par.children.length; i < j; i++) {
+				c.push(s ? m[par.children[i]].text : m[par.children[i]].text.toLowerCase());
+			}
+			if(!s) { n = n.toLowerCase(); }
+			switch(chk) {
+				case "delete_node":
+					return true;
+				case "rename_node":
+					i = ($.inArray(n, c) === -1 || (obj.text && obj.text[ s ? 'toString' : 'toLowerCase']() === n));
+					if(!i) {
+						this._data.core.last_error = { 'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_01', 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };
+					}
+					return i;
+				case "create_node":
+					i = ($.inArray(n, c) === -1);
+					if(!i) {
+						this._data.core.last_error = { 'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_04', 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };
+					}
+					return i;
+				case "copy_node":
+					i = ($.inArray(n, c) === -1);
+					if(!i) {
+						this._data.core.last_error = { 'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_02', 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };
+					}
+					return i;
+				case "move_node":
+					i = (obj.parent === par.id || $.inArray(n, c) === -1);
+					if(!i) {
+						this._data.core.last_error = { 'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_03', 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };
+					}
+					return i;
+			}
+			return true;
+		};
+		this.create_node = function (par, node, pos, callback, is_loaded) {
+			if(!node || node.text === undefined) {
+				if(par === null) {
+					par = "#";
+				}
+				par = this.get_node(par);
+				if(!par) {
+					return parent.create_node.call(this, par, node, pos, callback, is_loaded);
+				}
+				pos = pos === undefined ? "last" : pos;
+				if(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) {
+					return parent.create_node.call(this, par, node, pos, callback, is_loaded);
+				}
+				if(!node) { node = {}; }
+				var tmp, n, dpc, i, j, m = this._model.data, s = this.settings.unique.case_sensitive, cb = this.settings.unique.duplicate;
+				n = tmp = this.get_string('New node');
+				dpc = [];
+				for(i = 0, j = par.children.length; i < j; i++) {
+					dpc.push(s ? m[par.children[i]].text : m[par.children[i]].text.toLowerCase());
+				}
+				i = 1;
+				while($.inArray(s ? n : n.toLowerCase(), dpc) !== -1) {
+					n = cb.call(this, tmp, (++i)).toString();
+				}
+				node.text = n;
+			}
+			return parent.create_node.call(this, par, node, pos, callback, is_loaded);
+		};
+	};
+
+	// include the unique plugin by default
+	// $.jstree.defaults.plugins.push("unique");
+
+
+/**
+ * ### Wholerow plugin
+ *
+ * Makes each node appear block level. Making selection easier. May cause slow down for large trees in old browsers.
+ */
+
+	var div = document.createElement('DIV');
+	div.setAttribute('unselectable','on');
+	div.setAttribute('role','presentation');
+	div.className = 'jstree-wholerow';
+	div.innerHTML = '&#160;';
+	$.jstree.plugins.wholerow = function (options, parent) {
+		this.bind = function () {
+			parent.bind.call(this);
+
+			this.element
+				.on('ready.jstree set_state.jstree', $.proxy(function () {
+						this.hide_dots();
+					}, this))
+				.on("init.jstree loading.jstree ready.jstree", $.proxy(function () {
+						//div.style.height = this._data.core.li_height + 'px';
+						this.get_container_ul().addClass('jstree-wholerow-ul');
+					}, this))
+				.on("deselect_all.jstree", $.proxy(function (e, data) {
+						this.element.find('.jstree-wholerow-clicked').removeClass('jstree-wholerow-clicked');
+					}, this))
+				.on("changed.jstree", $.proxy(function (e, data) {
+						this.element.find('.jstree-wholerow-clicked').removeClass('jstree-wholerow-clicked');
+						var tmp = false, i, j;
+						for(i = 0, j = data.selected.length; i < j; i++) {
+							tmp = this.get_node(data.selected[i], true);
+							if(tmp && tmp.length) {
+								tmp.children('.jstree-wholerow').addClass('jstree-wholerow-clicked');
+							}
+						}
+					}, this))
+				.on("open_node.jstree", $.proxy(function (e, data) {
+						this.get_node(data.node, true).find('.jstree-clicked').parent().children('.jstree-wholerow').addClass('jstree-wholerow-clicked');
+					}, this))
+				.on("hover_node.jstree dehover_node.jstree", $.proxy(function (e, data) {
+						if(e.type === "hover_node" && this.is_disabled(data.node)) { return; }
+						this.get_node(data.node, true).children('.jstree-wholerow')[e.type === "hover_node"?"addClass":"removeClass"]('jstree-wholerow-hovered');
+					}, this))
+				.on("contextmenu.jstree", ".jstree-wholerow", $.proxy(function (e) {
+						e.preventDefault();
+						var tmp = $.Event('contextmenu', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : e.shiftKey, pageX : e.pageX, pageY : e.pageY });
+						$(e.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(tmp);
+					}, this))
+				.on("click.jstree", ".jstree-wholerow", function (e) {
+						e.stopImmediatePropagation();
+						var tmp = $.Event('click', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : e.shiftKey });
+						$(e.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(tmp).focus();
+					})
+				.on("click.jstree", ".jstree-leaf > .jstree-ocl", $.proxy(function (e) {
+						e.stopImmediatePropagation();
+						var tmp = $.Event('click', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : e.shiftKey });
+						$(e.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(tmp).focus();
+					}, this))
+				.on("mouseover.jstree", ".jstree-wholerow, .jstree-icon", $.proxy(function (e) {
+						e.stopImmediatePropagation();
+						if(!this.is_disabled(e.currentTarget)) {
+							this.hover_node(e.currentTarget);
+						}
+						return false;
+					}, this))
+				.on("mouseleave.jstree", ".jstree-node", $.proxy(function (e) {
+						this.dehover_node(e.currentTarget);
+					}, this));
+		};
+		this.teardown = function () {
+			if(this.settings.wholerow) {
+				this.element.find(".jstree-wholerow").remove();
+			}
+			parent.teardown.call(this);
+		};
+		this.redraw_node = function(obj, deep, callback, force_render) {
+			obj = parent.redraw_node.apply(this, arguments);
+			if(obj) {
+				var tmp = div.cloneNode(true);
+				//tmp.style.height = this._data.core.li_height + 'px';
+				if($.inArray(obj.id, this._data.core.selected) !== -1) { tmp.className += ' jstree-wholerow-clicked'; }
+				if(this._data.core.focused && this._data.core.focused === obj.id) { tmp.className += ' jstree-wholerow-hovered'; }
+				obj.insertBefore(tmp, obj.childNodes[0]);
+			}
+			return obj;
+		};
+	};
+	// include the wholerow plugin by default
+	// $.jstree.defaults.plugins.push("wholerow");
+
+
+(function ($) {
+	if(document.registerElement && Object && Object.create) {
+		var proto = Object.create(HTMLElement.prototype);
+		proto.createdCallback = function () {
+			var c = { core : {}, plugins : [] }, i;
+			for(i in $.jstree.plugins) {
+				if($.jstree.plugins.hasOwnProperty(i) && this.attributes[i]) {
+					c.plugins.push(i);
+					if(this.getAttribute(i) && JSON.parse(this.getAttribute(i))) {
+						c[i] = JSON.parse(this.getAttribute(i));
+					}
+				}
+			}
+			for(i in $.jstree.defaults.core) {
+				if($.jstree.defaults.core.hasOwnProperty(i) && this.attributes[i]) {
+					c.core[i] = JSON.parse(this.getAttribute(i)) || this.getAttribute(i);
+				}
+			}
+			jQuery(this).jstree(c);
+		};
+		// proto.attributeChangedCallback = function (name, previous, value) { };
+		try {
+			document.registerElement("vakata-jstree", { prototype: proto });
+		} catch(ignore) { }
+	}
+}(jQuery));
+}));
\ No newline at end of file
diff --git a/htdocs/Libs/jsTree/jstree.min.js b/htdocs/Libs/jsTree/jstree.min.js
new file mode 100644
index 0000000..e19446d
--- /dev/null
+++ b/htdocs/Libs/jsTree/jstree.min.js
@@ -0,0 +1,5 @@
+/*! jsTree - v3.0.9 - 2015-01-05 - (MIT) */
+!function(a){"use strict";"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a,b){"use strict";if(!a.jstree){var c=0,d=!1,e=!1,f=!1,g=[],h=a("script:last").attr("src"),i=document,j=i.createElement("LI"),k,l;j.setAttribute("role","treeitem"),k=i.createElement("I"),k.className="jstree-icon jstree-ocl",k.setAttribute("role","presentation"),j.appendChild(k),k=i.createElement("A"),k.className="jstree-anchor",k.setAttribute("href","#"),k.setAttribute("tabindex","-1"),l=i.createElement("I"),l.className="jstree-icon jstree-themeicon",l.setAttribute("role","presentation"),k.appendChild(l),j.appendChild(k),k=l=null,a.jstree={version:"3.0.9",defaults:{plugins:[]},plugins:{},path:h&&-1!==h.indexOf("/")?h.replace(/\/[^\/]+$/,""):"",idregex:/[\\:&!^|()\[\]<>@*'+~#";.,=\- \/${}%?`]/g},a.jstree.create=function(b,d){var e=new a.jstree.core(++c),f=d;return d=a.extend(!0,{},a.jstree.defaults,d),f&&f.plugins&&(d.plugins=f.plugins),a.each(d.plugins,function(a,b){"core"!==a&&(e=e.plugin(b,d[b]))}),e.init(b,d),e},a.jstree.destroy=function(){a(".jstree:jstree").jstree("destroy"),a(document).off(".jstree")},a.jstree.core=function(a){this._id=a,this._cnt=0,this._wrk=null,this._data={core:{themes:{name:!1,dots:!1,icons:!1},selected:[],last_error:{},working:!1,worker_queue:[],focused:null}}},a.jstree.reference=function(b){var c=null,d=null;if(b&&b.id&&(b=b.id),!d||!d.length)try{d=a(b)}catch(e){}if(!d||!d.length)try{d=a("#"+b.replace(a.jstree.idregex,"\\$&"))}catch(e){}return d&&d.length&&(d=d.closest(".jstree")).length&&(d=d.data("jstree"))?c=d:a(".jstree").each(function(){var d=a(this).data("jstree");return d&&d._model.data[b]?(c=d,!1):void 0}),c},a.fn.jstree=function(c){var d="string"==typeof c,e=Array.prototype.slice.call(arguments,1),f=null;return c!==!0||this.length?(this.each(function(){var g=a.jstree.reference(this),h=d&&g?g[c]:null;return f=d&&h?h.apply(g,e):null,g||d||c!==b&&!a.isPlainObject(c)||a(this).data("jstree",new a.jstree.create(this,c)),(g&&!d||c===!0)&&(f=g||!1),null!==f&&f!==b?!1:void 0}),null!==f&&f!==b?f:this):!1},a.expr[":"].jstree=a.expr.createPseudo(function(c){return function(c){return a(c).hasClass("jstree")&&a(c).data("jstree")!==b}}),a.jstree.defaults.core={data:!1,strings:!1,check_callback:!1,error:a.noop,animation:200,multiple:!0,themes:{name:!1,url:!1,dir:!1,dots:!0,icons:!0,stripes:!1,variant:!1,responsive:!1},expand_selected_onload:!0,worker:!0,force_text:!1,dblclick_toggle:!0},a.jstree.core.prototype={plugin:function(b,c){var d=a.jstree.plugins[b];return d?(this._data[b]={},d.prototype=this,new d(c,this)):this},init:function(b,c){this._model={data:{"#":{id:"#",parent:null,parents:[],children:[],children_d:[],state:{loaded:!1}}},changed:[],force_full_redraw:!1,redraw_timeout:!1,default_state:{loaded:!0,opened:!1,selected:!1,disabled:!1}},this.element=a(b).addClass("jstree jstree-"+this._id),this.settings=c,this._data.core.ready=!1,this._data.core.loaded=!1,this._data.core.rtl="rtl"===this.element.css("direction"),this.element[this._data.core.rtl?"addClass":"removeClass"]("jstree-rtl"),this.element.attr("role","tree"),this.settings.core.multiple&&this.element.attr("aria-multiselectable",!0),this.element.attr("tabindex")||this.element.attr("tabindex","0"),this.bind(),this.trigger("init"),this._data.core.original_container_html=this.element.find(" > ul > li").clone(!0),this._data.core.original_container_html.find("li").addBack().contents().filter(function(){return 3===this.nodeType&&(!this.nodeValue||/^\s+$/.test(this.nodeValue))}).remove(),this.element.html("<ul class='jstree-container-ul jstree-children' role='group'><li id='j"+this._id+"_loading' class='jstree-initial-node jstree-loading jstree-leaf jstree-last' role='tree-item'><i class='jstree-icon jstree-ocl'></i><a class='jstree-anchor' href='#'><i class='jstree-icon jstree-themeicon-hidden'></i>"+this.get_string("Loading ...")+"</a></li></ul>"),this.element.attr("aria-activedescendant","j"+this._id+"_loading"),this._data.core.li_height=this.get_container_ul().children("li").first().height()||24,this.trigger("loading"),this.load_node("#")},destroy:function(a){if(this._wrk)try{window.URL.revokeObjectURL(this._wrk),this._wrk=null}catch(b){}a||this.element.empty(),this.teardown()},teardown:function(){this.unbind(),this.element.removeClass("jstree").removeData("jstree").find("[class^='jstree']").addBack().attr("class",function(){return this.className.replace(/jstree[^ ]*|$/gi,"")}),this.element=null},bind:function(){var b="",c=null,d=0;this.element.on("dblclick.jstree",function(){if(document.selection&&document.selection.empty)document.selection.empty();else if(window.getSelection){var a=window.getSelection();try{a.removeAllRanges(),a.collapse()}catch(b){}}}).on("mousedown.jstree",a.proxy(function(a){a.target===this.element[0]&&(a.preventDefault(),d=+new Date)},this)).on("mousedown.jstree",".jstree-ocl",function(a){a.preventDefault()}).on("click.jstree",".jstree-ocl",a.proxy(function(a){this.toggle_node(a.target)},this)).on("dblclick.jstree",".jstree-anchor",a.proxy(function(a){this.settings.core.dblclick_toggle&&this.toggle_node(a.target)},this)).on("click.jstree",".jstree-anchor",a.proxy(function(b){b.preventDefault(),b.currentTarget!==document.activeElement&&a(b.currentTarget).focus(),this.activate_node(b.currentTarget,b)},this)).on("keydown.jstree",".jstree-anchor",a.proxy(function(b){if("INPUT"===b.target.tagName)return!0;var c=null;switch(this._data.core.rtl&&(37===b.which?b.which=39:39===b.which&&(b.which=37)),b.which){case 32:b.ctrlKey&&(b.type="click",a(b.currentTarget).trigger(b));break;case 13:b.type="click",a(b.currentTarget).trigger(b);break;case 37:b.preventDefault(),this.is_open(b.currentTarget)?this.close_node(b.currentTarget):(c=this.get_parent(b.currentTarget),c&&"#"!==c.id&&this.get_node(c,!0).children(".jstree-anchor").focus());break;case 38:b.preventDefault(),c=this.get_prev_dom(b.currentTarget),c&&c.length&&c.children(".jstree-anchor").focus();break;case 39:b.preventDefault(),this.is_closed(b.currentTarget)?this.open_node(b.currentTarget,function(a){this.get_node(a,!0).children(".jstree-anchor").focus()}):this.is_open(b.currentTarget)&&(c=this.get_node(b.currentTarget,!0).children(".jstree-children")[0],c&&a(this._firstChild(c)).children(".jstree-anchor").focus());break;case 40:b.preventDefault(),c=this.get_next_dom(b.currentTarget),c&&c.length&&c.children(".jstree-anchor").focus();break;case 106:this.open_all();break;case 36:b.preventDefault(),c=this._firstChild(this.get_container_ul()[0]),c&&a(c).children(".jstree-anchor").filter(":visible").focus();break;case 35:b.preventDefault(),this.element.find(".jstree-anchor").filter(":visible").last().focus()}},this)).on("load_node.jstree",a.proxy(function(b,c){c.status&&("#"!==c.node.id||this._data.core.loaded||(this._data.core.loaded=!0,this._firstChild(this.get_container_ul()[0])&&this.element.attr("aria-activedescendant",this._firstChild(this.get_container_ul()[0]).id),this.trigger("loaded")),this._data.core.ready||setTimeout(a.proxy(function(){if(!this.get_container_ul().find(".jstree-loading").length){if(this._data.core.ready=!0,this._data.core.selected.length){if(this.settings.core.expand_selected_onload){var b=[],c,d;for(c=0,d=this._data.core.selected.length;d>c;c++)b=b.concat(this._model.data[this._data.core.selected[c]].parents);for(b=a.vakata.array_unique(b),c=0,d=b.length;d>c;c++)this.open_node(b[c],!1,0)}this.trigger("changed",{action:"ready",selected:this._data.core.selected})}this.trigger("ready")}},this),0))},this)).on("keypress.jstree",a.proxy(function(d){if("INPUT"===d.target.tagName)return!0;c&&clearTimeout(c),c=setTimeout(function(){b=""},500);var e=String.fromCharCode(d.which).toLowerCase(),f=this.element.find(".jstree-anchor").filter(":visible"),g=f.index(document.activeElement)||0,h=!1;if(b+=e,b.length>1){if(f.slice(g).each(a.proxy(function(c,d){return 0===a(d).text().toLowerCase().indexOf(b)?(a(d).focus(),h=!0,!1):void 0},this)),h)return;if(f.slice(0,g).each(a.proxy(function(c,d){return 0===a(d).text().toLowerCase().indexOf(b)?(a(d).focus(),h=!0,!1):void 0},this)),h)return}if(new RegExp("^"+e+"+$").test(b)){if(f.slice(g+1).each(a.proxy(function(b,c){return a(c).text().toLowerCase().charAt(0)===e?(a(c).focus(),h=!0,!1):void 0},this)),h)return;if(f.slice(0,g+1).each(a.proxy(function(b,c){return a(c).text().toLowerCase().charAt(0)===e?(a(c).focus(),h=!0,!1):void 0},this)),h)return}},this)).on("init.jstree",a.proxy(function(){var a=this.settings.core.themes;this._data.core.themes.dots=a.dots,this._data.core.themes.stripes=a.stripes,this._data.core.themes.icons=a.icons,this.set_theme(a.name||"default",a.url),this.set_theme_variant(a.variant)},this)).on("loading.jstree",a.proxy(function(){this[this._data.core.themes.dots?"show_dots":"hide_dots"](),this[this._data.core.themes.icons?"show_icons":"hide_icons"](),this[this._data.core.themes.stripes?"show_stripes":"hide_stripes"]()},this)).on("blur.jstree",".jstree-anchor",a.proxy(function(b){this._data.core.focused=null,a(b.currentTarget).filter(".jstree-hovered").mouseleave(),this.element.attr("tabindex","0")},this)).on("focus.jstree",".jstree-anchor",a.proxy(function(b){var c=this.get_node(b.currentTarget);c&&c.id&&(this._data.core.focused=c.id),this.element.find(".jstree-hovered").not(b.currentTarget).mouseleave(),a(b.currentTarget).mouseenter(),this.element.attr("tabindex","-1")},this)).on("focus.jstree",a.proxy(function(){+new Date-d>500&&!this._data.core.focused&&(d=0,this.get_node(this.element.attr("aria-activedescendant"),!0).find("> .jstree-anchor").focus())},this)).on("mouseenter.jstree",".jstree-anchor",a.proxy(function(a){this.hover_node(a.currentTarget)},this)).on("mouseleave.jstree",".jstree-anchor",a.proxy(function(a){this.dehover_node(a.currentTarget)},this))},unbind:function(){this.element.off(".jstree"),a(document).off(".jstree-"+this._id)},trigger:function(a,b){b||(b={}),b.instance=this,this.element.triggerHandler(a.replace(".jstree","")+".jstree",b)},get_container:function(){return this.element},get_container_ul:function(){return this.element.children(".jstree-children").first()},get_string:function(b){var c=this.settings.core.strings;return a.isFunction(c)?c.call(this,b):c&&c[b]?c[b]:b},_firstChild:function(a){a=a?a.firstChild:null;while(null!==a&&1!==a.nodeType)a=a.nextSibling;return a},_nextSibling:function(a){a=a?a.nextSibling:null;while(null!==a&&1!==a.nodeType)a=a.nextSibling;return a},_previousSibling:function(a){a=a?a.previousSibling:null;while(null!==a&&1!==a.nodeType)a=a.previousSibling;return a},get_node:function(b,c){b&&b.id&&(b=b.id);var d;try{if(this._model.data[b])b=this._model.data[b];else if("string"==typeof b&&this._model.data[b.replace(/^#/,"")])b=this._model.data[b.replace(/^#/,"")];else if("string"==typeof b&&(d=a("#"+b.replace(a.jstree.idregex,"\\$&"),this.element)).length&&this._model.data[d.closest(".jstree-node").attr("id")])b=this._model.data[d.closest(".jstree-node").attr("id")];else if((d=a(b,this.element)).length&&this._model.data[d.closest(".jstree-node").attr("id")])b=this._model.data[d.closest(".jstree-node").attr("id")];else{if(!(d=a(b,this.element)).length||!d.hasClass("jstree"))return!1;b=this._model.data["#"]}return c&&(b="#"===b.id?this.element:a("#"+b.id.replace(a.jstree.idregex,"\\$&"),this.element)),b}catch(e){return!1}},get_path:function(a,b,c){if(a=a.parents?a:this.get_node(a),!a||"#"===a.id||!a.parents)return!1;var d,e,f=[];for(f.push(c?a.id:a.text),d=0,e=a.parents.length;e>d;d++)f.push(c?a.parents[d]:this.get_text(a.parents[d]));return f=f.reverse().slice(1),b?f.join(b):f},get_next_dom:function(b,c){var d;if(b=this.get_node(b,!0),b[0]===this.element[0]){d=this._firstChild(this.get_container_ul()[0]);while(d&&0===d.offsetHeight)d=this._nextSibling(d);return d?a(d):!1}if(!b||!b.length)return!1;if(c){d=b[0];do d=this._nextSibling(d);while(d&&0===d.offsetHeight);return d?a(d):!1}if(b.hasClass("jstree-open")){d=this._firstChild(b.children(".jstree-children")[0]);while(d&&0===d.offsetHeight)d=this._nextSibling(d);if(null!==d)return a(d)}d=b[0];do d=this._nextSibling(d);while(d&&0===d.offsetHeight);return null!==d?a(d):b.parentsUntil(".jstree",".jstree-node").next(".jstree-node:visible").first()},get_prev_dom:function(b,c){var d;if(b=this.get_node(b,!0),b[0]===this.element[0]){d=this.get_container_ul()[0].lastChild;while(d&&0===d.offsetHeight)d=this._previousSibling(d);return d?a(d):!1}if(!b||!b.length)return!1;if(c){d=b[0];do d=this._previousSibling(d);while(d&&0===d.offsetHeight);return d?a(d):!1}d=b[0];do d=this._previousSibling(d);while(d&&0===d.offsetHeight);if(null!==d){b=a(d);while(b.hasClass("jstree-open"))b=b.children(".jstree-children").first().children(".jstree-node:visible:last");return b}return d=b[0].parentNode.parentNode,d&&d.className&&-1!==d.className.indexOf("jstree-node")?a(d):!1},get_parent:function(a){return a=this.get_node(a),a&&"#"!==a.id?a.parent:!1},get_children_dom:function(a){return a=this.get_node(a,!0),a[0]===this.element[0]?this.get_container_ul().children(".jstree-node"):a&&a.length?a.children(".jstree-children").children(".jstree-node"):!1},is_parent:function(a){return a=this.get_node(a),a&&(a.state.loaded===!1||a.children.length>0)},is_loaded:function(a){return a=this.get_node(a),a&&a.state.loaded},is_loading:function(a){return a=this.get_node(a),a&&a.state&&a.state.loading},is_open:function(a){return a=this.get_node(a),a&&a.state.opened},is_closed:function(a){return a=this.get_node(a),a&&this.is_parent(a)&&!a.state.opened},is_leaf:function(a){return!this.is_parent(a)},load_node:function(b,c){var d,e,f,g,h;if(a.isArray(b))return this._load_nodes(b.slice(),c),!0;if(b=this.get_node(b),!b)return c&&c.call(this,b,!1),!1;if(b.state.loaded){for(b.state.loaded=!1,d=0,e=b.children_d.length;e>d;d++){for(f=0,g=b.parents.length;g>f;f++)this._model.data[b.parents[f]].children_d=a.vakata.array_remove_item(this._model.data[b.parents[f]].children_d,b.children_d[d]);this._model.data[b.children_d[d]].state.selected&&(h=!0,this._data.core.selected=a.vakata.array_remove_item(this._data.core.selected,b.children_d[d])),delete this._model.data[b.children_d[d]]}b.children=[],b.children_d=[],h&&this.trigger("changed",{action:"load_node",node:b,selected:this._data.core.selected})}return b.state.loading=!0,this.get_node(b,!0).addClass("jstree-loading").attr("aria-busy",!0),this._load_node(b,a.proxy(function(a){b=this._model.data[b.id],b.state.loading=!1,b.state.loaded=a;var d=this.get_node(b,!0);b.state.loaded&&!b.children.length&&d&&d.length&&!d.hasClass("jstree-leaf")&&d.removeClass("jstree-closed jstree-open").addClass("jstree-leaf"),d.removeClass("jstree-loading").attr("aria-busy",!1),this.trigger("load_node",{node:b,status:a}),c&&c.call(this,b,a)},this)),!0},_load_nodes:function(a,b,c){var d=!0,e=function(){this._load_nodes(a,b,!0)},f=this._model.data,g,h;for(g=0,h=a.length;h>g;g++)!f[a[g]]||f[a[g]].state.loaded&&c||(this.is_loading(a[g])||this.load_node(a[g],e),d=!1);d&&b&&!b.done&&(b.call(this,a),b.done=!0)},load_all:function(a,b){if(a||(a="#"),a=this.get_node(a),!a)return!1;var c=[],d=this._model.data,e=d[a.id].children_d,f,g;for(a.state&&!a.state.loaded&&c.push(a.id),f=0,g=e.length;g>f;f++)d[e[f]]&&d[e[f]].state&&!d[e[f]].state.loaded&&c.push(e[f]);c.length?this._load_nodes(c,function(){this.load_all(a,b)}):(b&&b.call(this,a),this.trigger("load_all",{node:a}))},_load_node:function(b,c){var d=this.settings.core.data,e;return d?a.isFunction(d)?d.call(this,b,a.proxy(function(d){d===!1&&c.call(this,!1),this["string"==typeof d?"_append_html_data":"_append_json_data"](b,"string"==typeof d?a(d):d,function(a){c.call(this,a)})},this)):"object"==typeof d?d.url?(d=a.extend(!0,{},d),a.isFunction(d.url)&&(d.url=d.url.call(this,b)),a.isFunction(d.data)&&(d.data=d.data.call(this,b)),a.ajax(d).done(a.proxy(function(d,e,f){var g=f.getResponseHeader("Content-Type");return-1!==g.indexOf("json")||"object"==typeof d?this._append_json_data(b,d,function(a){c.call(this,a)}):-1!==g.indexOf("html")||"string"==typeof d?this._append_html_data(b,a(d),function(a){c.call(this,a)}):(this._data.core.last_error={error:"ajax",plugin:"core",id:"core_04",reason:"Could not load node",data:JSON.stringify({id:b.id,xhr:f})},this.settings.core.error.call(this,this._data.core.last_error),c.call(this,!1))},this)).fail(a.proxy(function(a){c.call(this,!1),this._data.core.last_error={error:"ajax",plugin:"core",id:"core_04",reason:"Could not load node",data:JSON.stringify({id:b.id,xhr:a})},this.settings.core.error.call(this,this._data.core.last_error)},this))):(e=a.isArray(d)||a.isPlainObject(d)?JSON.parse(JSON.stringify(d)):d,"#"===b.id?this._append_json_data(b,e,function(a){c.call(this,a)}):(this._data.core.last_error={error:"nodata",plugin:"core",id:"core_05",reason:"Could not load node",data:JSON.stringify({id:b.id})},this.settings.core.error.call(this,this._data.core.last_error),c.call(this,!1))):"string"==typeof d?"#"===b.id?this._append_html_data(b,a(d),function(a){c.call(this,a)}):(this._data.core.last_error={error:"nodata",plugin:"core",id:"core_06",reason:"Could not load node",data:JSON.stringify({id:b.id})},this.settings.core.error.call(this,this._data.core.last_error),c.call(this,!1)):c.call(this,!1):"#"===b.id?this._append_html_data(b,this._data.core.original_container_html.clone(!0),function(a){c.call(this,a)}):c.call(this,!1)},_node_changed:function(a){a=this.get_node(a),a&&this._model.changed.push(a.id)},_append_html_data:function(b,c,d){b=this.get_node(b),b.children=[],b.children_d=[];var e=c.is("ul")?c.children():c,f=b.id,g=[],h=[],i=this._model.data,j=i[f],k=this._data.core.selected.length,l,m,n;for(e.each(a.proxy(function(b,c){l=this._parse_model_from_html(a(c),f,j.parents.concat()),l&&(g.push(l),h.push(l),i[l].children_d.length&&(h=h.concat(i[l].children_d)))},this)),j.children=g,j.children_d=h,m=0,n=j.parents.length;n>m;m++)i[j.parents[m]].children_d=i[j.parents[m]].children_d.concat(h);this.trigger("model",{nodes:h,parent:f}),"#"!==f?(this._node_changed(f),this.redraw()):(this.get_container_ul().children(".jstree-initial-node").remove(),this.redraw(!0)),this._data.core.selected.length!==k&&this.trigger("changed",{action:"model",selected:this._data.core.selected}),d.call(this,!0)},_append_json_data:function(b,c,d,e){b=this.get_node(b),b.children=[],b.children_d=[],c.d&&(c=c.d,"string"==typeof c&&(c=JSON.parse(c))),a.isArray(c)||(c=[c]);var f=null,g={df:this._model.default_state,dat:c,par:b.id,m:this._model.data,t_id:this._id,t_cnt:this._cnt,sel:this._data.core.selected},h=function(a,b){a.data&&(a=a.data);var c=a.dat,d=a.par,e=[],f=[],g=[],h=a.df,i=a.t_id,j=a.t_cnt,k=a.m,l=k[d],m=a.sel,n,o,p,q,r=function(a,c,d){d=d?d.concat():[],c&&d.unshift(c);var e=a.id.toString(),f,i,j,l,m={id:e,text:a.text||"",icon:a.icon!==b?a.icon:!0,parent:c,parents:d,children:a.children||[],children_d:a.children_d||[],data:a.data,state:{},li_attr:{id:!1},a_attr:{href:"#"},original:!1};for(f in h)h.hasOwnProperty(f)&&(m.state[f]=h[f]);if(a&&a.data&&a.data.jstree&&a.data.jstree.icon&&(m.icon=a.data.jstree.icon),a&&a.data&&(m.data=a.data,a.data.jstree))for(f in a.data.jstree)a.data.jstree.hasOwnProperty(f)&&(m.state[f]=a.data.jstree[f]);if(a&&"object"==typeof a.state)for(f in a.state)a.state.hasOwnProperty(f)&&(m.state[f]=a.state[f]);if(a&&"object"==typeof a.li_attr)for(f in a.li_attr)a.li_attr.hasOwnProperty(f)&&(m.li_attr[f]=a.li_attr[f]);if(m.li_attr.id||(m.li_attr.id=e),a&&"object"==typeof a.a_attr)for(f in a.a_attr)a.a_attr.hasOwnProperty(f)&&(m.a_attr[f]=a.a_attr[f]);for(a&&a.children&&a.children===!0&&(m.state.loaded=!1,m.children=[],m.children_d=[]),k[m.id]=m,f=0,i=m.children.length;i>f;f++)j=r(k[m.children[f]],m.id,d),l=k[j],m.children_d.push(j),l.children_d.length&&(m.children_d=m.children_d.concat(l.children_d));return delete a.data,delete a.children,k[m.id].original=a,m.state.selected&&g.push(m.id),m.id},s=function(a,c,d){d=d?d.concat():[],c&&d.unshift(c);var e=!1,f,l,m,n,o;do e="j"+i+"_"+ ++j;while(k[e]);o={id:!1,text:"string"==typeof a?a:"",icon:"object"==typeof a&&a.icon!==b?a.icon:!0,parent:c,parents:d,children:[],children_d:[],data:null,state:{},li_attr:{id:!1},a_attr:{href:"#"},original:!1};for(f in h)h.hasOwnProperty(f)&&(o.state[f]=h[f]);if(a&&a.id&&(o.id=a.id.toString()),a&&a.text&&(o.text=a.text),a&&a.data&&a.data.jstree&&a.data.jstree.icon&&(o.icon=a.data.jstree.icon),a&&a.data&&(o.data=a.data,a.data.jstree))for(f in a.data.jstree)a.data.jstree.hasOwnProperty(f)&&(o.state[f]=a.data.jstree[f]);if(a&&"object"==typeof a.state)for(f in a.state)a.state.hasOwnProperty(f)&&(o.state[f]=a.state[f]);if(a&&"object"==typeof a.li_attr)for(f in a.li_attr)a.li_attr.hasOwnProperty(f)&&(o.li_attr[f]=a.li_attr[f]);if(o.li_attr.id&&!o.id&&(o.id=o.li_attr.id.toString()),o.id||(o.id=e),o.li_attr.id||(o.li_attr.id=o.id),a&&"object"==typeof a.a_attr)for(f in a.a_attr)a.a_attr.hasOwnProperty(f)&&(o.a_attr[f]=a.a_attr[f]);if(a&&a.children&&a.children.length){for(f=0,l=a.children.length;l>f;f++)m=s(a.children[f],o.id,d),n=k[m],o.children.push(m),n.children_d.length&&(o.children_d=o.children_d.concat(n.children_d));o.children_d=o.children_d.concat(o.children)}return a&&a.children&&a.children===!0&&(o.state.loaded=!1,o.children=[],o.children_d=[]),delete a.data,delete a.children,o.original=a,k[o.id]=o,o.state.selected&&g.push(o.id),o.id};if(c.length&&c[0].id!==b&&c[0].parent!==b){for(o=0,p=c.length;p>o;o++)c[o].children||(c[o].children=[]),k[c[o].id.toString()]=c[o];for(o=0,p=c.length;p>o;o++)k[c[o].parent.toString()].children.push(c[o].id.toString()),l.children_d.push(c[o].id.toString());for(o=0,p=l.children.length;p>o;o++)n=r(k[l.children[o]],d,l.parents.concat()),f.push(n),k[n].children_d.length&&(f=f.concat(k[n].children_d));for(o=0,p=l.parents.length;p>o;o++)k[l.parents[o]].children_d=k[l.parents[o]].children_d.concat(f);q={cnt:j,mod:k,sel:m,par:d,dpc:f,add:g}}else{for(o=0,p=c.length;p>o;o++)n=s(c[o],d,l.parents.concat()),n&&(e.push(n),f.push(n),k[n].children_d.length&&(f=f.concat(k[n].children_d)));for(l.children=e,l.children_d=f,o=0,p=l.parents.length;p>o;o++)k[l.parents[o]].children_d=k[l.parents[o]].children_d.concat(f);q={cnt:j,mod:k,sel:m,par:d,dpc:f,add:g}}return"undefined"!=typeof window&&"undefined"!=typeof window.document?q:void postMessage(q)},i=function(b,c){if(this._cnt=b.cnt,this._model.data=b.mod,c){var e,f,g=b.add,h=b.sel,i=this._data.core.selected.slice(),j=this._model.data;if(h.length!==i.length||a.vakata.array_unique(h.concat(i)).length!==h.length){for(e=0,f=h.length;f>e;e++)-1===a.inArray(h[e],g)&&-1===a.inArray(h[e],i)&&(j[h[e]].state.selected=!1);for(e=0,f=i.length;f>e;e++)-1===a.inArray(i[e],h)&&(j[i[e]].state.selected=!0)}}b.add.length&&(this._data.core.selected=this._data.core.selected.concat(b.add)),this.trigger("model",{nodes:b.dpc,parent:b.par}),"#"!==b.par?(this._node_changed(b.par),this.redraw()):this.redraw(!0),b.add.length&&this.trigger("changed",{action:"model",selected:this._data.core.selected}),d.call(this,!0)};if(this.settings.core.worker&&window.Blob&&window.URL&&window.Worker)try{null===this._wrk&&(this._wrk=window.URL.createObjectURL(new window.Blob(["self.onmessage = "+h.toString()],{type:"text/javascript"}))),!this._data.core.working||e?(this._data.core.working=!0,f=new window.Worker(this._wrk),f.onmessage=a.proxy(function(a){i.call(this,a.data,!0);try{f.terminate(),f=null}catch(b){}this._data.core.worker_queue.length?this._append_json_data.apply(this,this._data.core.worker_queue.shift()):this._data.core.working=!1},this),g.par?f.postMessage(g):this._data.core.worker_queue.length?this._append_json_data.apply(this,this._data.core.worker_queue.shift()):this._data.core.working=!1):this._data.core.worker_queue.push([b,c,d,!0])}catch(j){i.call(this,h(g),!1),this._data.core.worker_queue.length?this._append_json_data.apply(this,this._data.core.worker_queue.shift()):this._data.core.working=!1}else i.call(this,h(g),!1)},_parse_model_from_html:function(b,c,d){d=d?[].concat(d):[],c&&d.unshift(c);var e,f,g=this._model.data,h={id:!1,text:!1,icon:!0,parent:c,parents:d,children:[],children_d:[],data:null,state:{},li_attr:{id:!1},a_attr:{href:"#"},original:!1},i,j,k;for(i in this._model.default_state)this._model.default_state.hasOwnProperty(i)&&(h.state[i]=this._model.default_state[i]);if(j=a.vakata.attributes(b,!0),a.each(j,function(b,c){return c=a.trim(c),c.length?(h.li_attr[b]=c,void("id"===b&&(h.id=c.toString()))):!0}),j=b.children("a").first(),j.length&&(j=a.vakata.attributes(j,!0),a.each(j,function(b,c){c=a.trim(c),c.length&&(h.a_attr[b]=c)})),j=b.children("a").first().length?b.children("a").first().clone():b.clone(),j.children("ins, i, ul").remove(),j=j.html(),j=a("<div />").html(j),h.text=this.settings.core.force_text?j.text():j.html(),j=b.data(),h.data=j?a.extend(!0,{},j):null,h.state.opened=b.hasClass("jstree-open"),h.state.selected=b.children("a").hasClass("jstree-clicked"),h.state.disabled=b.children("a").hasClass("jstree-disabled"),h.data&&h.data.jstree)for(i in h.data.jstree)h.data.jstree.hasOwnProperty(i)&&(h.state[i]=h.data.jstree[i]);j=b.children("a").children(".jstree-themeicon"),j.length&&(h.icon=j.hasClass("jstree-themeicon-hidden")?!1:j.attr("rel")),h.state.icon&&(h.icon=h.state.icon),j=b.children("ul").children("li");do k="j"+this._id+"_"+ ++this._cnt;while(g[k]);return h.id=h.li_attr.id?h.li_attr.id.toString():k,j.length?(j.each(a.proxy(function(b,c){e=this._parse_model_from_html(a(c),h.id,d),f=this._model.data[e],h.children.push(e),f.children_d.length&&(h.children_d=h.children_d.concat(f.children_d))},this)),h.children_d=h.children_d.concat(h.children)):b.hasClass("jstree-closed")&&(h.state.loaded=!1),h.li_attr["class"]&&(h.li_attr["class"]=h.li_attr["class"].replace("jstree-closed","").replace("jstree-open","")),h.a_attr["class"]&&(h.a_attr["class"]=h.a_attr["class"].replace("jstree-clicked","").replace("jstree-disabled","")),g[h.id]=h,h.state.selected&&this._data.core.selected.push(h.id),h.id},_parse_model_from_flat_json:function(a,c,d){d=d?d.concat():[],c&&d.unshift(c);var e=a.id.toString(),f=this._model.data,g=this._model.default_state,h,i,j,k,l={id:e,text:a.text||"",icon:a.icon!==b?a.icon:!0,parent:c,parents:d,children:a.children||[],children_d:a.children_d||[],data:a.data,state:{},li_attr:{id:!1},a_attr:{href:"#"},original:!1};for(h in g)g.hasOwnProperty(h)&&(l.state[h]=g[h]);if(a&&a.data&&a.data.jstree&&a.data.jstree.icon&&(l.icon=a.data.jstree.icon),a&&a.data&&(l.data=a.data,a.data.jstree))for(h in a.data.jstree)a.data.jstree.hasOwnProperty(h)&&(l.state[h]=a.data.jstree[h]);if(a&&"object"==typeof a.state)for(h in a.state)a.state.hasOwnProperty(h)&&(l.state[h]=a.state[h]);if(a&&"object"==typeof a.li_attr)for(h in a.li_attr)a.li_attr.hasOwnProperty(h)&&(l.li_attr[h]=a.li_attr[h]);if(l.li_attr.id||(l.li_attr.id=e),a&&"object"==typeof a.a_attr)for(h in a.a_attr)a.a_attr.hasOwnProperty(h)&&(l.a_attr[h]=a.a_attr[h]);for(a&&a.children&&a.children===!0&&(l.state.loaded=!1,l.children=[],l.children_d=[]),f[l.id]=l,h=0,i=l.children.length;i>h;h++)j=this._parse_model_from_flat_json(f[l.children[h]],l.id,d),k=f[j],l.children_d.push(j),k.children_d.length&&(l.children_d=l.children_d.concat(k.children_d));return delete a.data,delete a.children,f[l.id].original=a,l.state.selected&&this._data.core.selected.push(l.id),l.id},_parse_model_from_json:function(a,c,d){d=d?d.concat():[],c&&d.unshift(c);var e=!1,f,g,h,i,j=this._model.data,k=this._model.default_state,l;do e="j"+this._id+"_"+ ++this._cnt;while(j[e]);l={id:!1,text:"string"==typeof a?a:"",icon:"object"==typeof a&&a.icon!==b?a.icon:!0,parent:c,parents:d,children:[],children_d:[],data:null,state:{},li_attr:{id:!1},a_attr:{href:"#"},original:!1};for(f in k)k.hasOwnProperty(f)&&(l.state[f]=k[f]);if(a&&a.id&&(l.id=a.id.toString()),a&&a.text&&(l.text=a.text),a&&a.data&&a.data.jstree&&a.data.jstree.icon&&(l.icon=a.data.jstree.icon),a&&a.data&&(l.data=a.data,a.data.jstree))for(f in a.data.jstree)a.data.jstree.hasOwnProperty(f)&&(l.state[f]=a.data.jstree[f]);if(a&&"object"==typeof a.state)for(f in a.state)a.state.hasOwnProperty(f)&&(l.state[f]=a.state[f]);if(a&&"object"==typeof a.li_attr)for(f in a.li_attr)a.li_attr.hasOwnProperty(f)&&(l.li_attr[f]=a.li_attr[f]);if(l.li_attr.id&&!l.id&&(l.id=l.li_attr.id.toString()),l.id||(l.id=e),l.li_attr.id||(l.li_attr.id=l.id),a&&"object"==typeof a.a_attr)for(f in a.a_attr)a.a_attr.hasOwnProperty(f)&&(l.a_attr[f]=a.a_attr[f]);if(a&&a.children&&a.children.length){for(f=0,g=a.children.length;g>f;f++)h=this._parse_model_from_json(a.children[f],l.id,d),i=j[h],l.children.push(h),i.children_d.length&&(l.children_d=l.children_d.concat(i.children_d));l.children_d=l.children_d.concat(l.children)}return a&&a.children&&a.children===!0&&(l.state.loaded=!1,l.children=[],l.children_d=[]),delete a.data,delete a.children,l.original=a,j[l.id]=l,l.state.selected&&this._data.core.selected.push(l.id),l.id},_redraw:function(){var a=this._model.force_full_redraw?this._model.data["#"].children.concat([]):this._model.changed.concat([]),b=document.createElement("UL"),c,d,e,f=this._data.core.focused;for(d=0,e=a.length;e>d;d++)c=this.redraw_node(a[d],!0,this._model.force_full_redraw),c&&this._model.force_full_redraw&&b.appendChild(c);this._model.force_full_redraw&&(b.className=this.get_container_ul()[0].className,b.setAttribute("role","group"),this.element.empty().append(b)),null!==f&&(c=this.get_node(f,!0),c&&c.length&&c.children(".jstree-anchor")[0]!==document.activeElement?c.children(".jstree-anchor").focus():this._data.core.focused=null),this._model.force_full_redraw=!1,this._model.changed=[],this.trigger("redraw",{nodes:a})},redraw:function(a){a&&(this._model.force_full_redraw=!0),this._redraw()},draw_children:function(a){var b=this.get_node(a),c=!1,d=!1,e=!1,f=document;if(!b)return!1;if("#"===b.id)return this.redraw(!0);if(a=this.get_node(a,!0),!a||!a.length)return!1;if(a.children(".jstree-children").remove(),a=a[0],b.children.length&&b.state.loaded){for(e=f.createElement("UL"),e.setAttribute("role","group"),e.className="jstree-children",c=0,d=b.children.length;d>c;c++)e.appendChild(this.redraw_node(b.children[c],!0,!0));a.appendChild(e)}},redraw_node:function(b,c,d,e){var f=this.get_node(b),g=!1,h=!1,i=!1,k=!1,l=!1,m=!1,n="",o=document,p=this._model.data,q=!1,r=!1,s=null,t=0,u=0;if(!f)return!1;if("#"===f.id)return this.redraw(!0);if(c=c||0===f.children.length,b=document.querySelector?this.element[0].querySelector("#"+(-1!=="0123456789".indexOf(f.id[0])?"\\3"+f.id[0]+" "+f.id.substr(1).replace(a.jstree.idregex,"\\$&"):f.id.replace(a.jstree.idregex,"\\$&"))):document.getElementById(f.id))b=a(b),d||(g=b.parent().parent()[0],g===this.element[0]&&(g=null),h=b.index()),c||!f.children.length||b.children(".jstree-children").length||(c=!0),c||(i=b.children(".jstree-children")[0]),q=b.children(".jstree-anchor")[0]===document.activeElement,b.remove();else if(c=!0,!d){if(g="#"!==f.parent?a("#"+f.parent.replace(a.jstree.idregex,"\\$&"),this.element)[0]:null,!(null===g||g&&p[f.parent].state.opened))return!1;h=a.inArray(f.id,null===g?p["#"].children:p[f.parent].children)}b=j.cloneNode(!0),n="jstree-node ";for(k in f.li_attr)if(f.li_attr.hasOwnProperty(k)){if("id"===k)continue;"class"!==k?b.setAttribute(k,f.li_attr[k]):n+=f.li_attr[k]}f.a_attr.id||(f.a_attr.id=f.id+"_anchor"),b.setAttribute("aria-selected",!!f.state.selected),b.setAttribute("aria-level",f.parents.length),b.setAttribute("aria-labelledby",f.a_attr.id),f.state.disabled&&b.setAttribute("aria-disabled",!0),f.state.loaded&&!f.children.length?n+=" jstree-leaf":(n+=f.state.opened&&f.state.loaded?" jstree-open":" jstree-closed",b.setAttribute("aria-expanded",f.state.opened&&f.state.loaded)),null!==f.parent&&p[f.parent].children[p[f.parent].children.length-1]===f.id&&(n+=" jstree-last"),b.id=f.id,b.className=n,n=(f.state.selected?" jstree-clicked":"")+(f.state.disabled?" jstree-disabled":"");for(l in f.a_attr)if(f.a_attr.hasOwnProperty(l)){if("href"===l&&"#"===f.a_attr[l])continue;"class"!==l?b.childNodes[1].setAttribute(l,f.a_attr[l]):n+=" "+f.a_attr[l]}if(n.length&&(b.childNodes[1].className="jstree-anchor "+n),(f.icon&&f.icon!==!0||f.icon===!1)&&(f.icon===!1?b.childNodes[1].childNodes[0].className+=" jstree-themeicon-hidden":-1===f.icon.indexOf("/")&&-1===f.icon.indexOf(".")?b.childNodes[1].childNodes[0].className+=" "+f.icon+" jstree-themeicon-custom":(b.childNodes[1].childNodes[0].style.backgroundImage="url("+f.icon+")",b.childNodes[1].childNodes[0].style.backgroundPosition="center center",b.childNodes[1].childNodes[0].style.backgroundSize="auto",b.childNodes[1].childNodes[0].className+=" jstree-themeicon-custom")),this.settings.core.force_text?b.childNodes[1].appendChild(o.createTextNode(f.text)):b.childNodes[1].innerHTML+=f.text,c&&f.children.length&&(f.state.opened||e)&&f.state.loaded){for(m=o.createElement("UL"),m.setAttribute("role","group"),m.className="jstree-children",k=0,l=f.children.length;l>k;k++)m.appendChild(this.redraw_node(f.children[k],c,!0));
+b.appendChild(m)}if(i&&b.appendChild(i),!d){for(g||(g=this.element[0]),k=0,l=g.childNodes.length;l>k;k++)if(g.childNodes[k]&&g.childNodes[k].className&&-1!==g.childNodes[k].className.indexOf("jstree-children")){s=g.childNodes[k];break}s||(s=o.createElement("UL"),s.setAttribute("role","group"),s.className="jstree-children",g.appendChild(s)),g=s,h<g.childNodes.length?g.insertBefore(b,g.childNodes[h]):g.appendChild(b),q&&(t=this.element[0].scrollTop,u=this.element[0].scrollLeft,b.childNodes[1].focus(),this.element[0].scrollTop=t,this.element[0].scrollLeft=u)}return f.state.opened&&!f.state.loaded&&(f.state.opened=!1,setTimeout(a.proxy(function(){this.open_node(f.id,!1,0)},this),0)),b},open_node:function(c,d,e){var f,g,h,i;if(a.isArray(c)){for(c=c.slice(),f=0,g=c.length;g>f;f++)this.open_node(c[f],d,e);return!0}if(c=this.get_node(c),!c||"#"===c.id)return!1;if(e=e===b?this.settings.core.animation:e,!this.is_closed(c))return d&&d.call(this,c,!1),!1;if(this.is_loaded(c))h=this.get_node(c,!0),i=this,h.length&&(e&&h.children(".jstree-children").length&&h.children(".jstree-children").stop(!0,!0),c.children.length&&!this._firstChild(h.children(".jstree-children")[0])&&this.draw_children(c),e?(this.trigger("before_open",{node:c}),h.children(".jstree-children").css("display","none").end().removeClass("jstree-closed").addClass("jstree-open").attr("aria-expanded",!0).children(".jstree-children").stop(!0,!0).slideDown(e,function(){this.style.display="",i.trigger("after_open",{node:c})})):(this.trigger("before_open",{node:c}),h[0].className=h[0].className.replace("jstree-closed","jstree-open"),h[0].setAttribute("aria-expanded",!0))),c.state.opened=!0,d&&d.call(this,c,!0),h.length||this.trigger("before_open",{node:c}),this.trigger("open_node",{node:c}),e&&h.length||this.trigger("after_open",{node:c});else{if(this.is_loading(c))return setTimeout(a.proxy(function(){this.open_node(c,d,e)},this),500);this.load_node(c,function(a,b){return b?this.open_node(a,d,e):d?d.call(this,a,!1):!1})}},_open_to:function(b){if(b=this.get_node(b),!b||"#"===b.id)return!1;var c,d,e=b.parents;for(c=0,d=e.length;d>c;c+=1)"#"!==c&&this.open_node(e[c],!1,0);return a("#"+b.id.replace(a.jstree.idregex,"\\$&"),this.element)},close_node:function(c,d){var e,f,g,h;if(a.isArray(c)){for(c=c.slice(),e=0,f=c.length;f>e;e++)this.close_node(c[e],d);return!0}return c=this.get_node(c),c&&"#"!==c.id?this.is_closed(c)?!1:(d=d===b?this.settings.core.animation:d,g=this,h=this.get_node(c,!0),h.length&&(d?h.children(".jstree-children").attr("style","display:block !important").end().removeClass("jstree-open").addClass("jstree-closed").attr("aria-expanded",!1).children(".jstree-children").stop(!0,!0).slideUp(d,function(){this.style.display="",h.children(".jstree-children").remove(),g.trigger("after_close",{node:c})}):(h[0].className=h[0].className.replace("jstree-open","jstree-closed"),h.attr("aria-expanded",!1).children(".jstree-children").remove())),c.state.opened=!1,this.trigger("close_node",{node:c}),void(d&&h.length||this.trigger("after_close",{node:c}))):!1},toggle_node:function(b){var c,d;if(a.isArray(b)){for(b=b.slice(),c=0,d=b.length;d>c;c++)this.toggle_node(b[c]);return!0}return this.is_closed(b)?this.open_node(b):this.is_open(b)?this.close_node(b):void 0},open_all:function(a,b,c){if(a||(a="#"),a=this.get_node(a),!a)return!1;var d="#"===a.id?this.get_container_ul():this.get_node(a,!0),e,f,g;if(!d.length){for(e=0,f=a.children_d.length;f>e;e++)this.is_closed(this._model.data[a.children_d[e]])&&(this._model.data[a.children_d[e]].state.opened=!0);return this.trigger("open_all",{node:a})}c=c||d,g=this,d=this.is_closed(a)?d.find(".jstree-closed").addBack():d.find(".jstree-closed"),d.each(function(){g.open_node(this,function(a,d){d&&this.is_parent(a)&&this.open_all(a,b,c)},b||0)}),0===c.find(".jstree-closed").length&&this.trigger("open_all",{node:this.get_node(c)})},close_all:function(b,c){if(b||(b="#"),b=this.get_node(b),!b)return!1;var d="#"===b.id?this.get_container_ul():this.get_node(b,!0),e=this,f,g;if(!d.length){for(f=0,g=b.children_d.length;g>f;f++)this._model.data[b.children_d[f]].state.opened=!1;return this.trigger("close_all",{node:b})}d=this.is_open(b)?d.find(".jstree-open").addBack():d.find(".jstree-open"),a(d.get().reverse()).each(function(){e.close_node(this,c||0)}),this.trigger("close_all",{node:b})},is_disabled:function(a){return a=this.get_node(a),a&&a.state&&a.state.disabled},enable_node:function(b){var c,d;if(a.isArray(b)){for(b=b.slice(),c=0,d=b.length;d>c;c++)this.enable_node(b[c]);return!0}return b=this.get_node(b),b&&"#"!==b.id?(b.state.disabled=!1,this.get_node(b,!0).children(".jstree-anchor").removeClass("jstree-disabled").attr("aria-disabled",!1),void this.trigger("enable_node",{node:b})):!1},disable_node:function(b){var c,d;if(a.isArray(b)){for(b=b.slice(),c=0,d=b.length;d>c;c++)this.disable_node(b[c]);return!0}return b=this.get_node(b),b&&"#"!==b.id?(b.state.disabled=!0,this.get_node(b,!0).children(".jstree-anchor").addClass("jstree-disabled").attr("aria-disabled",!0),void this.trigger("disable_node",{node:b})):!1},activate_node:function(a,c){if(this.is_disabled(a))return!1;if(this._data.core.last_clicked=this._data.core.last_clicked&&this._data.core.last_clicked.id!==b?this.get_node(this._data.core.last_clicked.id):null,this._data.core.last_clicked&&!this._data.core.last_clicked.state.selected&&(this._data.core.last_clicked=null),!this._data.core.last_clicked&&this._data.core.selected.length&&(this._data.core.last_clicked=this.get_node(this._data.core.selected[this._data.core.selected.length-1])),this.settings.core.multiple&&(c.metaKey||c.ctrlKey||c.shiftKey)&&(!c.shiftKey||this._data.core.last_clicked&&this.get_parent(a)&&this.get_parent(a)===this._data.core.last_clicked.parent))if(c.shiftKey){var d=this.get_node(a).id,e=this._data.core.last_clicked.id,f=this.get_node(this._data.core.last_clicked.parent).children,g=!1,h,i;for(h=0,i=f.length;i>h;h+=1)f[h]===d&&(g=!g),f[h]===e&&(g=!g),g||f[h]===d||f[h]===e?this.select_node(f[h],!0,!1,c):this.deselect_node(f[h],!0,c);this.trigger("changed",{action:"select_node",node:this.get_node(a),selected:this._data.core.selected,event:c})}else this.is_selected(a)?this.deselect_node(a,!1,c):this.select_node(a,!1,!1,c);else!this.settings.core.multiple&&(c.metaKey||c.ctrlKey||c.shiftKey)&&this.is_selected(a)?this.deselect_node(a,!1,c):(this.deselect_all(!0),this.select_node(a,!1,!1,c),this._data.core.last_clicked=this.get_node(a));this.trigger("activate_node",{node:this.get_node(a)})},hover_node:function(a){if(a=this.get_node(a,!0),!a||!a.length||a.children(".jstree-hovered").length)return!1;var b=this.element.find(".jstree-hovered"),c=this.element;b&&b.length&&this.dehover_node(b),a.children(".jstree-anchor").addClass("jstree-hovered"),this.trigger("hover_node",{node:this.get_node(a)}),setTimeout(function(){c.attr("aria-activedescendant",a[0].id)},0)},dehover_node:function(a){return a=this.get_node(a,!0),a&&a.length&&a.children(".jstree-hovered").length?(a.children(".jstree-anchor").removeClass("jstree-hovered"),void this.trigger("dehover_node",{node:this.get_node(a)})):!1},select_node:function(b,c,d,e){var f,g,h,i;if(a.isArray(b)){for(b=b.slice(),g=0,h=b.length;h>g;g++)this.select_node(b[g],c,d,e);return!0}return b=this.get_node(b),b&&"#"!==b.id?(f=this.get_node(b,!0),void(b.state.selected||(b.state.selected=!0,this._data.core.selected.push(b.id),d||(f=this._open_to(b)),f&&f.length&&f.attr("aria-selected",!0).children(".jstree-anchor").addClass("jstree-clicked"),this.trigger("select_node",{node:b,selected:this._data.core.selected,event:e}),c||this.trigger("changed",{action:"select_node",node:b,selected:this._data.core.selected,event:e})))):!1},deselect_node:function(b,c,d){var e,f,g;if(a.isArray(b)){for(b=b.slice(),e=0,f=b.length;f>e;e++)this.deselect_node(b[e],c,d);return!0}return b=this.get_node(b),b&&"#"!==b.id?(g=this.get_node(b,!0),void(b.state.selected&&(b.state.selected=!1,this._data.core.selected=a.vakata.array_remove_item(this._data.core.selected,b.id),g.length&&g.attr("aria-selected",!1).children(".jstree-anchor").removeClass("jstree-clicked"),this.trigger("deselect_node",{node:b,selected:this._data.core.selected,event:d}),c||this.trigger("changed",{action:"deselect_node",node:b,selected:this._data.core.selected,event:d})))):!1},select_all:function(a){var b=this._data.core.selected.concat([]),c,d;for(this._data.core.selected=this._model.data["#"].children_d.concat(),c=0,d=this._data.core.selected.length;d>c;c++)this._model.data[this._data.core.selected[c]]&&(this._model.data[this._data.core.selected[c]].state.selected=!0);this.redraw(!0),this.trigger("select_all",{selected:this._data.core.selected}),a||this.trigger("changed",{action:"select_all",selected:this._data.core.selected,old_selection:b})},deselect_all:function(a){var b=this._data.core.selected.concat([]),c,d;for(c=0,d=this._data.core.selected.length;d>c;c++)this._model.data[this._data.core.selected[c]]&&(this._model.data[this._data.core.selected[c]].state.selected=!1);this._data.core.selected=[],this.element.find(".jstree-clicked").removeClass("jstree-clicked").parent().attr("aria-selected",!1),this.trigger("deselect_all",{selected:this._data.core.selected,node:b}),a||this.trigger("changed",{action:"deselect_all",selected:this._data.core.selected,old_selection:b})},is_selected:function(a){return a=this.get_node(a),a&&"#"!==a.id?a.state.selected:!1},get_selected:function(b){return b?a.map(this._data.core.selected,a.proxy(function(a){return this.get_node(a)},this)):this._data.core.selected.slice()},get_top_selected:function(b){var c=this.get_selected(!0),d={},e,f,g,h;for(e=0,f=c.length;f>e;e++)d[c[e].id]=c[e];for(e=0,f=c.length;f>e;e++)for(g=0,h=c[e].children_d.length;h>g;g++)d[c[e].children_d[g]]&&delete d[c[e].children_d[g]];c=[];for(e in d)d.hasOwnProperty(e)&&c.push(e);return b?a.map(c,a.proxy(function(a){return this.get_node(a)},this)):c},get_bottom_selected:function(b){var c=this.get_selected(!0),d=[],e,f;for(e=0,f=c.length;f>e;e++)c[e].children.length||d.push(c[e].id);return b?a.map(d,a.proxy(function(a){return this.get_node(a)},this)):d},get_state:function(){var a={core:{open:[],scroll:{left:this.element.scrollLeft(),top:this.element.scrollTop()},selected:[]}},b;for(b in this._model.data)this._model.data.hasOwnProperty(b)&&"#"!==b&&(this._model.data[b].state.opened&&a.core.open.push(b),this._model.data[b].state.selected&&a.core.selected.push(b));return a},set_state:function(c,d){if(c){if(c.core){var e,f,g,h;if(c.core.open)return a.isArray(c.core.open)?(e=!0,f=!1,g=this,a.each(c.core.open.concat([]),function(b,h){f=g.get_node(h),f&&(g.is_loaded(h)?(g.is_closed(h)&&g.open_node(h,!1,0),c&&c.core&&c.core.open&&a.vakata.array_remove_item(c.core.open,h)):(g.is_loading(h)||g.open_node(h,a.proxy(function(b,e){!e&&c&&c.core&&c.core.open&&a.vakata.array_remove_item(c.core.open,b.id),this.set_state(c,d)},g),0),e=!1))}),e&&(delete c.core.open,this.set_state(c,d)),!1):(delete c.core.open,this.set_state(c,d),!1);if(c.core.scroll)return c.core.scroll&&c.core.scroll.left!==b&&this.element.scrollLeft(c.core.scroll.left),c.core.scroll&&c.core.scroll.top!==b&&this.element.scrollTop(c.core.scroll.top),delete c.core.scroll,this.set_state(c,d),!1;if(c.core.selected)return h=this,this.deselect_all(),a.each(c.core.selected,function(a,b){h.select_node(b)}),delete c.core.selected,this.set_state(c,d),!1;if(a.isEmptyObject(c.core))return delete c.core,this.set_state(c,d),!1}return a.isEmptyObject(c)?(c=null,d&&d.call(this),this.trigger("set_state"),!1):!0}return!1},refresh:function(b,c){this._data.core.state=c===!0?{}:this.get_state(),c&&a.isFunction(c)&&(this._data.core.state=c.call(this,this._data.core.state)),this._cnt=0,this._model.data={"#":{id:"#",parent:null,parents:[],children:[],children_d:[],state:{loaded:!1}}};var d=this.get_container_ul()[0].className;b||(this.element.html("<ul class='"+d+"' role='group'><li class='jstree-initial-node jstree-loading jstree-leaf jstree-last' role='treeitem' id='j"+this._id+"_loading'><i class='jstree-icon jstree-ocl'></i><a class='jstree-anchor' href='#'><i class='jstree-icon jstree-themeicon-hidden'></i>"+this.get_string("Loading ...")+"</a></li></ul>"),this.element.attr("aria-activedescendant","j"+this._id+"_loading")),this.load_node("#",function(b,c){c&&(this.get_container_ul()[0].className=d,this._firstChild(this.get_container_ul()[0])&&this.element.attr("aria-activedescendant",this._firstChild(this.get_container_ul()[0]).id),this.set_state(a.extend(!0,{},this._data.core.state),function(){this.trigger("refresh")})),this._data.core.state=null})},refresh_node:function(b){if(b=this.get_node(b),!b||"#"===b.id)return!1;var c=[],d=[],e=this._data.core.selected.concat([]);d.push(b.id),b.state.opened===!0&&c.push(b.id),this.get_node(b,!0).find(".jstree-open").each(function(){c.push(this.id)}),this._load_nodes(d,a.proxy(function(a){this.open_node(c,!1,0),this.select_node(this._data.core.selected),this.trigger("refresh_node",{node:b,nodes:a})},this))},set_id:function(b,c){if(b=this.get_node(b),!b||"#"===b.id)return!1;var d,e,f=this._model.data;for(c=c.toString(),f[b.parent].children[a.inArray(b.id,f[b.parent].children)]=c,d=0,e=b.parents.length;e>d;d++)f[b.parents[d]].children_d[a.inArray(b.id,f[b.parents[d]].children_d)]=c;for(d=0,e=b.children.length;e>d;d++)f[b.children[d]].parent=c;for(d=0,e=b.children_d.length;e>d;d++)f[b.children_d[d]].parents[a.inArray(b.id,f[b.children_d[d]].parents)]=c;return d=a.inArray(b.id,this._data.core.selected),-1!==d&&(this._data.core.selected[d]=c),d=this.get_node(b.id,!0),d&&d.attr("id",c),delete f[b.id],b.id=c,f[c]=b,!0},get_text:function(a){return a=this.get_node(a),a&&"#"!==a.id?a.text:!1},set_text:function(b,c){var d,e;if(a.isArray(b)){for(b=b.slice(),d=0,e=b.length;e>d;d++)this.set_text(b[d],c);return!0}return b=this.get_node(b),b&&"#"!==b.id?(b.text=c,this.get_node(b,!0).length&&this.redraw_node(b.id),this.trigger("set_text",{obj:b,text:c}),!0):!1},get_json:function(b,c,d){if(b=this.get_node(b||"#"),!b)return!1;c&&c.flat&&!d&&(d=[]);var e={id:b.id,text:b.text,icon:this.get_icon(b),li_attr:a.extend(!0,{},b.li_attr),a_attr:a.extend(!0,{},b.a_attr),state:{},data:c&&c.no_data?!1:a.extend(!0,{},b.data)},f,g;if(c&&c.flat?e.parent=b.parent:e.children=[],!c||!c.no_state)for(f in b.state)b.state.hasOwnProperty(f)&&(e.state[f]=b.state[f]);if(c&&c.no_id&&(delete e.id,e.li_attr&&e.li_attr.id&&delete e.li_attr.id,e.a_attr&&e.a_attr.id&&delete e.a_attr.id),c&&c.flat&&"#"!==b.id&&d.push(e),!c||!c.no_children)for(f=0,g=b.children.length;g>f;f++)c&&c.flat?this.get_json(b.children[f],c,d):e.children.push(this.get_json(b.children[f],c));return c&&c.flat?d:"#"===b.id?e.children:e},create_node:function(c,d,e,f,g){if(null===c&&(c="#"),c=this.get_node(c),!c)return!1;if(e=e===b?"last":e,!e.toString().match(/^(before|after)$/)&&!g&&!this.is_loaded(c))return this.load_node(c,function(){this.create_node(c,d,e,f,!0)});d||(d={text:this.get_string("New node")}),"string"==typeof d&&(d={text:d}),d.text===b&&(d.text=this.get_string("New node"));var h,i,j,k;switch("#"===c.id&&("before"===e&&(e="first"),"after"===e&&(e="last")),e){case"before":h=this.get_node(c.parent),e=a.inArray(c.id,h.children),c=h;break;case"after":h=this.get_node(c.parent),e=a.inArray(c.id,h.children)+1,c=h;break;case"inside":case"first":e=0;break;case"last":e=c.children.length;break;default:e||(e=0)}if(e>c.children.length&&(e=c.children.length),d.id||(d.id=!0),!this.check("create_node",d,c,e))return this.settings.core.error.call(this,this._data.core.last_error),!1;if(d.id===!0&&delete d.id,d=this._parse_model_from_json(d,c.id,c.parents.concat()),!d)return!1;for(h=this.get_node(d),i=[],i.push(d),i=i.concat(h.children_d),this.trigger("model",{nodes:i,parent:c.id}),c.children_d=c.children_d.concat(i),j=0,k=c.parents.length;k>j;j++)this._model.data[c.parents[j]].children_d=this._model.data[c.parents[j]].children_d.concat(i);for(d=h,h=[],j=0,k=c.children.length;k>j;j++)h[j>=e?j+1:j]=c.children[j];return h[e]=d.id,c.children=h,this.redraw_node(c,!0),f&&f.call(this,this.get_node(d)),this.trigger("create_node",{node:this.get_node(d),parent:c.id,position:e}),d.id},rename_node:function(b,c){var d,e,f;if(a.isArray(b)){for(b=b.slice(),d=0,e=b.length;e>d;d++)this.rename_node(b[d],c);return!0}return b=this.get_node(b),b&&"#"!==b.id?(f=b.text,this.check("rename_node",b,this.get_parent(b),c)?(this.set_text(b,c),this.trigger("rename_node",{node:b,text:c,old:f}),!0):(this.settings.core.error.call(this,this._data.core.last_error),!1)):!1},delete_node:function(b){var c,d,e,f,g,h,i,j,k,l;if(a.isArray(b)){for(b=b.slice(),c=0,d=b.length;d>c;c++)this.delete_node(b[c]);return!0}if(b=this.get_node(b),!b||"#"===b.id)return!1;if(e=this.get_node(b.parent),f=a.inArray(b.id,e.children),l=!1,!this.check("delete_node",b,e,f))return this.settings.core.error.call(this,this._data.core.last_error),!1;for(-1!==f&&(e.children=a.vakata.array_remove(e.children,f)),g=b.children_d.concat([]),g.push(b.id),j=0,k=g.length;k>j;j++){for(h=0,i=b.parents.length;i>h;h++)f=a.inArray(g[j],this._model.data[b.parents[h]].children_d),-1!==f&&(this._model.data[b.parents[h]].children_d=a.vakata.array_remove(this._model.data[b.parents[h]].children_d,f));this._model.data[g[j]].state.selected&&(l=!0,f=a.inArray(g[j],this._data.core.selected),-1!==f&&(this._data.core.selected=a.vakata.array_remove(this._data.core.selected,f)))}for(this.trigger("delete_node",{node:b,parent:e.id}),l&&this.trigger("changed",{action:"delete_node",node:b,selected:this._data.core.selected,parent:e.id}),j=0,k=g.length;k>j;j++)delete this._model.data[g[j]];return this.redraw_node(e,!0),!0},check:function(b,c,d,e,f){c=c&&c.id?c:this.get_node(c),d=d&&d.id?d:this.get_node(d);var g=b.match(/^move_node|copy_node|create_node$/i)?d:c,h=this.settings.core.check_callback;return"move_node"!==b&&"copy_node"!==b||f&&f.is_multi||c.id!==d.id&&a.inArray(c.id,d.children)!==e&&-1===a.inArray(d.id,c.children_d)?(g&&g.data&&(g=g.data),g&&g.functions&&(g.functions[b]===!1||g.functions[b]===!0)?(g.functions[b]===!1&&(this._data.core.last_error={error:"check",plugin:"core",id:"core_02",reason:"Node data prevents function: "+b,data:JSON.stringify({chk:b,pos:e,obj:c&&c.id?c.id:!1,par:d&&d.id?d.id:!1})}),g.functions[b]):h===!1||a.isFunction(h)&&h.call(this,b,c,d,e,f)===!1||h&&h[b]===!1?(this._data.core.last_error={error:"check",plugin:"core",id:"core_03",reason:"User config for core.check_callback prevents function: "+b,data:JSON.stringify({chk:b,pos:e,obj:c&&c.id?c.id:!1,par:d&&d.id?d.id:!1})},!1):!0):(this._data.core.last_error={error:"check",plugin:"core",id:"core_01",reason:"Moving parent inside child",data:JSON.stringify({chk:b,pos:e,obj:c&&c.id?c.id:!1,par:d&&d.id?d.id:!1})},!1)},last_error:function(){return this._data.core.last_error},move_node:function(c,d,e,f,g,h){var i,j,k,l,m,n,o,p,q,r,s,t,u,v;if(d=this.get_node(d),e=e===b?0:e,!d)return!1;if(!e.toString().match(/^(before|after)$/)&&!g&&!this.is_loaded(d))return this.load_node(d,function(){this.move_node(c,d,e,f,!0)});if(a.isArray(c)){for(c=c.slice(),i=0,j=c.length;j>i;i++)this.move_node(c[i],d,e,f,g,!0)&&(d=c[i],e="after");return this.redraw(),!0}if(c=c&&c.id?c:this.get_node(c),!c||"#"===c.id)return!1;if(k=(c.parent||"#").toString(),m=e.toString().match(/^(before|after)$/)&&"#"!==d.id?this.get_node(d.parent):d,n=c.instance?c.instance:this._model.data[c.id]?this:a.jstree.reference(c.id),o=!n||!n._id||this._id!==n._id,l=n&&n._id&&k&&n._model.data[k]&&n._model.data[k].children?a.inArray(c.id,n._model.data[k].children):-1,o)return this.copy_node(c,d,e,f,g)?(n&&n.delete_node(c),!0):!1;switch("#"===d.id&&("before"===e&&(e="first"),"after"===e&&(e="last")),e){case"before":e=a.inArray(d.id,m.children);break;case"after":e=a.inArray(d.id,m.children)+1;break;case"inside":case"first":e=0;break;case"last":e=m.children.length;break;default:e||(e=0)}if(e>m.children.length&&(e=m.children.length),!this.check("move_node",c,m,e,{core:!0,is_multi:n&&n._id&&n._id!==this._id,is_foreign:!n||!n._id}))return this.settings.core.error.call(this,this._data.core.last_error),!1;if(c.parent===m.id){for(p=m.children.concat(),q=a.inArray(c.id,p),-1!==q&&(p=a.vakata.array_remove(p,q),e>q&&e--),q=[],r=0,s=p.length;s>r;r++)q[r>=e?r+1:r]=p[r];q[e]=c.id,m.children=q,this._node_changed(m.id),this.redraw("#"===m.id)}else{for(q=c.children_d.concat(),q.push(c.id),r=0,s=c.parents.length;s>r;r++){for(p=[],v=n._model.data[c.parents[r]].children_d,t=0,u=v.length;u>t;t++)-1===a.inArray(v[t],q)&&p.push(v[t]);n._model.data[c.parents[r]].children_d=p}for(n._model.data[k].children=a.vakata.array_remove_item(n._model.data[k].children,c.id),r=0,s=m.parents.length;s>r;r++)this._model.data[m.parents[r]].children_d=this._model.data[m.parents[r]].children_d.concat(q);for(p=[],r=0,s=m.children.length;s>r;r++)p[r>=e?r+1:r]=m.children[r];for(p[e]=c.id,m.children=p,m.children_d.push(c.id),m.children_d=m.children_d.concat(c.children_d),c.parent=m.id,q=m.parents.concat(),q.unshift(m.id),v=c.parents.length,c.parents=q,q=q.concat(),r=0,s=c.children_d.length;s>r;r++)this._model.data[c.children_d[r]].parents=this._model.data[c.children_d[r]].parents.slice(0,-1*v),Array.prototype.push.apply(this._model.data[c.children_d[r]].parents,q);("#"===k||"#"===m.id)&&(this._model.force_full_redraw=!0),this._model.force_full_redraw||(this._node_changed(k),this._node_changed(m.id)),h||this.redraw()}return f&&f.call(this,c,m,e),this.trigger("move_node",{node:c,parent:m.id,position:e,old_parent:k,old_position:l,is_multi:n&&n._id&&n._id!==this._id,is_foreign:!n||!n._id,old_instance:n,new_instance:this}),!0},copy_node:function(c,d,e,f,g,h){var i,j,k,l,m,n,o,p,q,r,s;if(d=this.get_node(d),e=e===b?0:e,!d)return!1;if(!e.toString().match(/^(before|after)$/)&&!g&&!this.is_loaded(d))return this.load_node(d,function(){this.copy_node(c,d,e,f,!0)});if(a.isArray(c)){for(c=c.slice(),i=0,j=c.length;j>i;i++)l=this.copy_node(c[i],d,e,f,g,!0),l&&(d=l,e="after");return this.redraw(),!0}if(c=c&&c.id?c:this.get_node(c),!c||"#"===c.id)return!1;switch(p=(c.parent||"#").toString(),q=e.toString().match(/^(before|after)$/)&&"#"!==d.id?this.get_node(d.parent):d,r=c.instance?c.instance:this._model.data[c.id]?this:a.jstree.reference(c.id),s=!r||!r._id||this._id!==r._id,"#"===d.id&&("before"===e&&(e="first"),"after"===e&&(e="last")),e){case"before":e=a.inArray(d.id,q.children);break;case"after":e=a.inArray(d.id,q.children)+1;break;case"inside":case"first":e=0;break;case"last":e=q.children.length;break;default:e||(e=0)}if(e>q.children.length&&(e=q.children.length),!this.check("copy_node",c,q,e,{core:!0,is_multi:r&&r._id&&r._id!==this._id,is_foreign:!r||!r._id}))return this.settings.core.error.call(this,this._data.core.last_error),!1;if(o=r?r.get_json(c,{no_id:!0,no_data:!0,no_state:!0}):c,!o)return!1;if(o.id===!0&&delete o.id,o=this._parse_model_from_json(o,q.id,q.parents.concat()),!o)return!1;for(l=this.get_node(o),c&&c.state&&c.state.loaded===!1&&(l.state.loaded=!1),k=[],k.push(o),k=k.concat(l.children_d),this.trigger("model",{nodes:k,parent:q.id}),m=0,n=q.parents.length;n>m;m++)this._model.data[q.parents[m]].children_d=this._model.data[q.parents[m]].children_d.concat(k);for(k=[],m=0,n=q.children.length;n>m;m++)k[m>=e?m+1:m]=q.children[m];return k[e]=l.id,q.children=k,q.children_d.push(l.id),q.children_d=q.children_d.concat(l.children_d),"#"===q.id&&(this._model.force_full_redraw=!0),this._model.force_full_redraw||this._node_changed(q.id),h||this.redraw("#"===q.id),f&&f.call(this,l,q,e),this.trigger("copy_node",{node:l,original:c,parent:q.id,position:e,old_parent:p,old_position:r&&r._id&&p&&r._model.data[p]&&r._model.data[p].children?a.inArray(c.id,r._model.data[p].children):-1,is_multi:r&&r._id&&r._id!==this._id,is_foreign:!r||!r._id,old_instance:r,new_instance:this}),l.id},cut:function(b){if(b||(b=this._data.core.selected.concat()),a.isArray(b)||(b=[b]),!b.length)return!1;var c=[],g,h,i;for(h=0,i=b.length;i>h;h++)g=this.get_node(b[h]),g&&g.id&&"#"!==g.id&&c.push(g);return c.length?(d=c,f=this,e="move_node",void this.trigger("cut",{node:b})):!1},copy:function(b){if(b||(b=this._data.core.selected.concat()),a.isArray(b)||(b=[b]),!b.length)return!1;var c=[],g,h,i;for(h=0,i=b.length;i>h;h++)g=this.get_node(b[h]),g&&g.id&&"#"!==g.id&&c.push(g);return c.length?(d=c,f=this,e="copy_node",void this.trigger("copy",{node:b})):!1},get_buffer:function(){return{mode:e,node:d,inst:f}},can_paste:function(){return e!==!1&&d!==!1},paste:function(a,b){return a=this.get_node(a),a&&e&&e.match(/^(copy_node|move_node)$/)&&d?(this[e](d,a,b)&&this.trigger("paste",{parent:a.id,node:d,mode:e}),d=!1,e=!1,void(f=!1)):!1},clear_buffer:function(){d=!1,e=!1,f=!1,this.trigger("clear_buffer")},edit:function(b,c){if(b=this.get_node(b),!b)return!1;if(this.settings.core.check_callback===!1)return this._data.core.last_error={error:"check",plugin:"core",id:"core_07",reason:"Could not edit node because of check_callback"},this.settings.core.error.call(this,this._data.core.last_error),!1;c="string"==typeof c?c:b.text,this.set_text(b,""),b=this._open_to(b);var d=this._data.core.rtl,e=this.element.width(),f=b.children(".jstree-anchor"),g=a("<span>"),h=c,i=a("<div />",{css:{position:"absolute",top:"-200px",left:d?"0px":"-1000px",visibility:"hidden"}}).appendTo("body"),j=a("<input />",{value:h,"class":"jstree-rename-input",css:{padding:"0",border:"1px solid silver","box-sizing":"border-box",display:"inline-block",height:this._data.core.li_height+"px",lineHeight:this._data.core.li_height+"px",width:"150px"},blur:a.proxy(function(){var c=g.children(".jstree-rename-input"),d=c.val();""===d&&(d=h),i.remove(),g.replaceWith(f),g.remove(),this.set_text(b,h),this.rename_node(b,a("<div></div>").text(d)[this.settings.core.force_text?"text":"html"]())===!1&&this.set_text(b,h)},this),keydown:function(a){var b=a.which;27===b&&(this.value=h),(27===b||13===b||37===b||38===b||39===b||40===b||32===b)&&a.stopImmediatePropagation(),(27===b||13===b)&&(a.preventDefault(),this.blur())},click:function(a){a.stopImmediatePropagation()},mousedown:function(a){a.stopImmediatePropagation()},keyup:function(a){j.width(Math.min(i.text("pW"+this.value).width(),e))},keypress:function(a){return 13===a.which?!1:void 0}}),k={fontFamily:f.css("fontFamily")||"",fontSize:f.css("fontSize")||"",fontWeight:f.css("fontWeight")||"",fontStyle:f.css("fontStyle")||"",fontStretch:f.css("fontStretch")||"",fontVariant:f.css("fontVariant")||"",letterSpacing:f.css("letterSpacing")||"",wordSpacing:f.css("wordSpacing")||""};g.attr("class",f.attr("class")).append(f.contents().clone()).append(j),f.replaceWith(g),i.css(k),j.css(k).width(Math.min(i.text("pW"+j[0].value).width(),e))[0].select()},set_theme:function(b,c){if(!b)return!1;if(c===!0){var d=this.settings.core.themes.dir;d||(d=a.jstree.path+"/themes"),c=d+"/"+b+"/style.css"}c&&-1===a.inArray(c,g)&&(a("head").append('<link rel="stylesheet" href="'+c+'" type="text/css" />'),g.push(c)),this._data.core.themes.name&&this.element.removeClass("jstree-"+this._data.core.themes.name),this._data.core.themes.name=b,this.element.addClass("jstree-"+b),this.element[this.settings.core.themes.responsive?"addClass":"removeClass"]("jstree-"+b+"-responsive"),this.trigger("set_theme",{theme:b})},get_theme:function(){return this._data.core.themes.name},set_theme_variant:function(a){this._data.core.themes.variant&&this.element.removeClass("jstree-"+this._data.core.themes.name+"-"+this._data.core.themes.variant),this._data.core.themes.variant=a,a&&this.element.addClass("jstree-"+this._data.core.themes.name+"-"+this._data.core.themes.variant)},get_theme_variant:function(){return this._data.core.themes.variant},show_stripes:function(){this._data.core.themes.stripes=!0,this.get_container_ul().addClass("jstree-striped")},hide_stripes:function(){this._data.core.themes.stripes=!1,this.get_container_ul().removeClass("jstree-striped")},toggle_stripes:function(){this._data.core.themes.stripes?this.hide_stripes():this.show_stripes()},show_dots:function(){this._data.core.themes.dots=!0,this.get_container_ul().removeClass("jstree-no-dots")},hide_dots:function(){this._data.core.themes.dots=!1,this.get_container_ul().addClass("jstree-no-dots")},toggle_dots:function(){this._data.core.themes.dots?this.hide_dots():this.show_dots()},show_icons:function(){this._data.core.themes.icons=!0,this.get_container_ul().removeClass("jstree-no-icons")},hide_icons:function(){this._data.core.themes.icons=!1,this.get_container_ul().addClass("jstree-no-icons")},toggle_icons:function(){this._data.core.themes.icons?this.hide_icons():this.show_icons()},set_icon:function(b,c){var d,e,f,g;if(a.isArray(b)){for(b=b.slice(),d=0,e=b.length;e>d;d++)this.set_icon(b[d],c);return!0}return b=this.get_node(b),b&&"#"!==b.id?(g=b.icon,b.icon=c,f=this.get_node(b,!0).children(".jstree-anchor").children(".jstree-themeicon"),c===!1?this.hide_icon(b):c===!0?(f.removeClass("jstree-themeicon-custom "+g).css("background","").removeAttr("rel"),g===!1&&this.show_icon(b)):-1===c.indexOf("/")&&-1===c.indexOf(".")?(f.removeClass(g).css("background",""),f.addClass(c+" jstree-themeicon-custom").attr("rel",c),g===!1&&this.show_icon(b)):(f.removeClass(g).css("background",""),f.addClass("jstree-themeicon-custom").css("background","url('"+c+"') center center no-repeat").attr("rel",c),g===!1&&this.show_icon(b)),!0):!1},get_icon:function(a){return a=this.get_node(a),a&&"#"!==a.id?a.icon:!1},hide_icon:function(b){var c,d;if(a.isArray(b)){for(b=b.slice(),c=0,d=b.length;d>c;c++)this.hide_icon(b[c]);return!0}return b=this.get_node(b),b&&"#"!==b?(b.icon=!1,this.get_node(b,!0).children(".jstree-anchor").children(".jstree-themeicon").addClass("jstree-themeicon-hidden"),!0):!1},show_icon:function(b){var c,d,e;if(a.isArray(b)){for(b=b.slice(),c=0,d=b.length;d>c;c++)this.show_icon(b[c]);return!0}return b=this.get_node(b),b&&"#"!==b?(e=this.get_node(b,!0),b.icon=e.length?e.children(".jstree-anchor").children(".jstree-themeicon").attr("rel"):!0,b.icon||(b.icon=!0),e.children(".jstree-anchor").children(".jstree-themeicon").removeClass("jstree-themeicon-hidden"),!0):!1}},a.vakata={},a.vakata.attributes=function(b,c){b=a(b)[0];var d=c?{}:[];return b&&b.attributes&&a.each(b.attributes,function(b,e){-1===a.inArray(e.name.toLowerCase(),["style","contenteditable","hasfocus","tabindex"])&&null!==e.value&&""!==a.trim(e.value)&&(c?d[e.name]=e.value:d.push(e.name))}),d},a.vakata.array_unique=function(a){var b=[],c,d,e;for(c=0,e=a.length;e>c;c++){for(d=0;c>=d;d++)if(a[c]===a[d])break;d===c&&b.push(a[c])}return b},a.vakata.array_remove=function(a,b,c){var d=a.slice((c||b)+1||a.length);return a.length=0>b?a.length+b:b,a.push.apply(a,d),a},a.vakata.array_remove_item=function(b,c){var d=a.inArray(c,b);return-1!==d?a.vakata.array_remove(b,d):b};var m=document.createElement("I");m.className="jstree-icon jstree-checkbox",m.setAttribute("role","presentation"),a.jstree.defaults.checkbox={visible:!0,three_state:!0,whole_node:!0,keep_selected_style:!0,cascade:"",tie_selection:!0},a.jstree.plugins.checkbox=function(b,c){this.bind=function(){c.bind.call(this),this._data.checkbox.uto=!1,this._data.checkbox.selected=[],this.settings.checkbox.three_state&&(this.settings.checkbox.cascade="up+down+undetermined"),this.element.on("init.jstree",a.proxy(function(){this._data.checkbox.visible=this.settings.checkbox.visible,this.settings.checkbox.keep_selected_style||this.element.addClass("jstree-checkbox-no-clicked"),this.settings.checkbox.tie_selection&&this.element.addClass("jstree-checkbox-selection")},this)).on("loading.jstree",a.proxy(function(){this[this._data.checkbox.visible?"show_checkboxes":"hide_checkboxes"]()},this)),-1!==this.settings.checkbox.cascade.indexOf("undetermined")&&this.element.on("changed.jstree uncheck_node.jstree check_node.jstree uncheck_all.jstree check_all.jstree move_node.jstree copy_node.jstree redraw.jstree open_node.jstree",a.proxy(function(){this._data.checkbox.uto&&clearTimeout(this._data.checkbox.uto),this._data.checkbox.uto=setTimeout(a.proxy(this._undetermined,this),50)},this)),this.settings.checkbox.tie_selection||this.element.on("model.jstree",a.proxy(function(a,b){var c=this._model.data,d=c[b.parent],e=b.nodes,f,g;
+for(f=0,g=e.length;g>f;f++)c[e[f]].state.checked=c[e[f]].original&&c[e[f]].original.state&&c[e[f]].original.state.checked,c[e[f]].state.checked&&this._data.checkbox.selected.push(e[f])},this)),(-1!==this.settings.checkbox.cascade.indexOf("up")||-1!==this.settings.checkbox.cascade.indexOf("down"))&&this.element.on("model.jstree",a.proxy(function(b,c){var d=this._model.data,e=d[c.parent],f=c.nodes,g=[],h,i,j,k,l,m,n=this.settings.checkbox.cascade,o=this.settings.checkbox.tie_selection;if(-1!==n.indexOf("down"))if(e.state[o?"selected":"checked"]){for(i=0,j=f.length;j>i;i++)d[f[i]].state[o?"selected":"checked"]=!0;this._data[o?"core":"checkbox"].selected=this._data[o?"core":"checkbox"].selected.concat(f)}else for(i=0,j=f.length;j>i;i++)if(d[f[i]].state[o?"selected":"checked"]){for(k=0,l=d[f[i]].children_d.length;l>k;k++)d[d[f[i]].children_d[k]].state[o?"selected":"checked"]=!0;this._data[o?"core":"checkbox"].selected=this._data[o?"core":"checkbox"].selected.concat(d[f[i]].children_d)}if(-1!==n.indexOf("up")){for(i=0,j=e.children_d.length;j>i;i++)d[e.children_d[i]].children.length||g.push(d[e.children_d[i]].parent);for(g=a.vakata.array_unique(g),k=0,l=g.length;l>k;k++){e=d[g[k]];while(e&&"#"!==e.id){for(h=0,i=0,j=e.children.length;j>i;i++)h+=d[e.children[i]].state[o?"selected":"checked"];if(h!==j)break;e.state[o?"selected":"checked"]=!0,this._data[o?"core":"checkbox"].selected.push(e.id),m=this.get_node(e,!0),m&&m.length&&m.attr("aria-selected",!0).children(".jstree-anchor").addClass(o?"jstree-clicked":"jstree-checked"),e=this.get_node(e.parent)}}}this._data[o?"core":"checkbox"].selected=a.vakata.array_unique(this._data[o?"core":"checkbox"].selected)},this)).on(this.settings.checkbox.tie_selection?"select_node.jstree":"check_node.jstree",a.proxy(function(b,c){var d=c.node,e=this._model.data,f=this.get_node(d.parent),g=this.get_node(d,!0),h,i,j,k,l=this.settings.checkbox.cascade,m=this.settings.checkbox.tie_selection;if(-1!==l.indexOf("down"))for(this._data[m?"core":"checkbox"].selected=a.vakata.array_unique(this._data[m?"core":"checkbox"].selected.concat(d.children_d)),h=0,i=d.children_d.length;i>h;h++)k=e[d.children_d[h]],k.state[m?"selected":"checked"]=!0,k&&k.original&&k.original.state&&k.original.state.undetermined&&(k.original.state.undetermined=!1);if(-1!==l.indexOf("up"))while(f&&"#"!==f.id){for(j=0,h=0,i=f.children.length;i>h;h++)j+=e[f.children[h]].state[m?"selected":"checked"];if(j!==i)break;f.state[m?"selected":"checked"]=!0,this._data[m?"core":"checkbox"].selected.push(f.id),k=this.get_node(f,!0),k&&k.length&&k.attr("aria-selected",!0).children(".jstree-anchor").addClass(m?"jstree-clicked":"jstree-checked"),f=this.get_node(f.parent)}-1!==l.indexOf("down")&&g.length&&g.find(".jstree-anchor").addClass(m?"jstree-clicked":"jstree-checked").parent().attr("aria-selected",!0)},this)).on(this.settings.checkbox.tie_selection?"deselect_all.jstree":"uncheck_all.jstree",a.proxy(function(a,b){var c=this.get_node("#"),d=this._model.data,e,f,g;for(e=0,f=c.children_d.length;f>e;e++)g=d[c.children_d[e]],g&&g.original&&g.original.state&&g.original.state.undetermined&&(g.original.state.undetermined=!1)},this)).on(this.settings.checkbox.tie_selection?"deselect_node.jstree":"uncheck_node.jstree",a.proxy(function(b,c){var d=c.node,e=this.get_node(d,!0),f,g,h,i=this.settings.checkbox.cascade,j=this.settings.checkbox.tie_selection;if(d&&d.original&&d.original.state&&d.original.state.undetermined&&(d.original.state.undetermined=!1),-1!==i.indexOf("down"))for(f=0,g=d.children_d.length;g>f;f++)h=this._model.data[d.children_d[f]],h.state[j?"selected":"checked"]=!1,h&&h.original&&h.original.state&&h.original.state.undetermined&&(h.original.state.undetermined=!1);if(-1!==i.indexOf("up"))for(f=0,g=d.parents.length;g>f;f++)h=this._model.data[d.parents[f]],h.state[j?"selected":"checked"]=!1,h&&h.original&&h.original.state&&h.original.state.undetermined&&(h.original.state.undetermined=!1),h=this.get_node(d.parents[f],!0),h&&h.length&&h.attr("aria-selected",!1).children(".jstree-anchor").removeClass(j?"jstree-clicked":"jstree-checked");for(h=[],f=0,g=this._data[j?"core":"checkbox"].selected.length;g>f;f++)-1!==i.indexOf("down")&&-1!==a.inArray(this._data[j?"core":"checkbox"].selected[f],d.children_d)||-1!==i.indexOf("up")&&-1!==a.inArray(this._data[j?"core":"checkbox"].selected[f],d.parents)||h.push(this._data[j?"core":"checkbox"].selected[f]);this._data[j?"core":"checkbox"].selected=a.vakata.array_unique(h),-1!==i.indexOf("down")&&e.length&&e.find(".jstree-anchor").removeClass(j?"jstree-clicked":"jstree-checked").parent().attr("aria-selected",!1)},this)),-1!==this.settings.checkbox.cascade.indexOf("up")&&this.element.on("delete_node.jstree",a.proxy(function(a,b){var c=this.get_node(b.parent),d=this._model.data,e,f,g,h,i=this.settings.checkbox.tie_selection;while(c&&"#"!==c.id){for(g=0,e=0,f=c.children.length;f>e;e++)g+=d[c.children[e]].state[i?"selected":"checked"];if(g!==f)break;c.state[i?"selected":"checked"]=!0,this._data[i?"core":"checkbox"].selected.push(c.id),h=this.get_node(c,!0),h&&h.length&&h.attr("aria-selected",!0).children(".jstree-anchor").addClass(i?"jstree-clicked":"jstree-checked"),c=this.get_node(c.parent)}},this)).on("move_node.jstree",a.proxy(function(b,c){var d=c.is_multi,e=c.old_parent,f=this.get_node(c.parent),g=this._model.data,h,i,j,k,l,m=this.settings.checkbox.tie_selection;if(!d){h=this.get_node(e);while(h&&"#"!==h.id){for(i=0,j=0,k=h.children.length;k>j;j++)i+=g[h.children[j]].state[m?"selected":"checked"];if(i!==k)break;h.state[m?"selected":"checked"]=!0,this._data[m?"core":"checkbox"].selected.push(h.id),l=this.get_node(h,!0),l&&l.length&&l.attr("aria-selected",!0).children(".jstree-anchor").addClass(m?"jstree-clicked":"jstree-checked"),h=this.get_node(h.parent)}}h=f;while(h&&"#"!==h.id){for(i=0,j=0,k=h.children.length;k>j;j++)i+=g[h.children[j]].state[m?"selected":"checked"];if(i===k)h.state[m?"selected":"checked"]||(h.state[m?"selected":"checked"]=!0,this._data[m?"core":"checkbox"].selected.push(h.id),l=this.get_node(h,!0),l&&l.length&&l.attr("aria-selected",!0).children(".jstree-anchor").addClass(m?"jstree-clicked":"jstree-checked"));else{if(!h.state[m?"selected":"checked"])break;h.state[m?"selected":"checked"]=!1,this._data[m?"core":"checkbox"].selected=a.vakata.array_remove_item(this._data[m?"core":"checkbox"].selected,h.id),l=this.get_node(h,!0),l&&l.length&&l.attr("aria-selected",!1).children(".jstree-anchor").removeClass(m?"jstree-clicked":"jstree-checked")}h=this.get_node(h.parent)}},this))},this._undetermined=function(){var b,c,d=this._model.data,e=this.settings.checkbox.tie_selection,f=this._data[e?"core":"checkbox"].selected,g=[],h=this;for(b=0,c=f.length;c>b;b++)d[f[b]]&&d[f[b]].parents&&(g=g.concat(d[f[b]].parents));for(this.element.find(".jstree-closed").not(":has(.jstree-children)").each(function(){var a=h.get_node(this),e;if(a.state.loaded)for(b=0,c=a.children_d.length;c>b;b++)e=d[a.children_d[b]],!e.state.loaded&&e.original&&e.original.state&&e.original.state.undetermined&&e.original.state.undetermined===!0&&(g.push(e.id),g=g.concat(e.parents));else a.original&&a.original.state&&a.original.state.undetermined&&a.original.state.undetermined===!0&&(g.push(a.id),g=g.concat(a.parents))}),g=a.vakata.array_unique(g),g=a.vakata.array_remove_item(g,"#"),this.element.find(".jstree-undetermined").removeClass("jstree-undetermined"),b=0,c=g.length;c>b;b++)d[g[b]].state[e?"selected":"checked"]||(f=this.get_node(g[b],!0),f&&f.length&&f.children(".jstree-anchor").children(".jstree-checkbox").addClass("jstree-undetermined"))},this.redraw_node=function(b,d,e,f){if(b=c.redraw_node.apply(this,arguments)){var g,h,i=null;for(g=0,h=b.childNodes.length;h>g;g++)if(b.childNodes[g]&&b.childNodes[g].className&&-1!==b.childNodes[g].className.indexOf("jstree-anchor")){i=b.childNodes[g];break}i&&(!this.settings.checkbox.tie_selection&&this._model.data[b.id].state.checked&&(i.className+=" jstree-checked"),i.insertBefore(m.cloneNode(!1),i.childNodes[0]))}return e||-1===this.settings.checkbox.cascade.indexOf("undetermined")||(this._data.checkbox.uto&&clearTimeout(this._data.checkbox.uto),this._data.checkbox.uto=setTimeout(a.proxy(this._undetermined,this),50)),b},this.show_checkboxes=function(){this._data.core.themes.checkboxes=!0,this.get_container_ul().removeClass("jstree-no-checkboxes")},this.hide_checkboxes=function(){this._data.core.themes.checkboxes=!1,this.get_container_ul().addClass("jstree-no-checkboxes")},this.toggle_checkboxes=function(){this._data.core.themes.checkboxes?this.hide_checkboxes():this.show_checkboxes()},this.is_undetermined=function(b){b=this.get_node(b);var c=this.settings.checkbox.cascade,d,e,f=this.settings.checkbox.tie_selection,g=this._data[f?"core":"checkbox"].selected,h=this._model.data;if(!b||b.state[f?"selected":"checked"]===!0||-1===c.indexOf("undetermined")||-1===c.indexOf("down")&&-1===c.indexOf("up"))return!1;if(!b.state.loaded&&b.original.state.undetermined===!0)return!0;for(d=0,e=b.children_d.length;e>d;d++)if(-1!==a.inArray(b.children_d[d],g)||!h[b.children_d[d]].state.loaded&&h[b.children_d[d]].original.state.undetermined)return!0;return!1},this.activate_node=function(b,d){return this.settings.checkbox.tie_selection&&(this.settings.checkbox.whole_node||a(d.target).hasClass("jstree-checkbox"))&&(d.ctrlKey=!0),this.settings.checkbox.tie_selection||!this.settings.checkbox.whole_node&&!a(d.target).hasClass("jstree-checkbox")?c.activate_node.call(this,b,d):this.is_disabled(b)?!1:(this.is_checked(b)?this.uncheck_node(b,d):this.check_node(b,d),void this.trigger("activate_node",{node:this.get_node(b)}))},this.check_node=function(b,c){if(this.settings.checkbox.tie_selection)return this.select_node(b,!1,!0,c);var d,e,f,g;if(a.isArray(b)){for(b=b.slice(),e=0,f=b.length;f>e;e++)this.check_node(b[e],c);return!0}return b=this.get_node(b),b&&"#"!==b.id?(d=this.get_node(b,!0),void(b.state.checked||(b.state.checked=!0,this._data.checkbox.selected.push(b.id),d&&d.length&&d.children(".jstree-anchor").addClass("jstree-checked"),this.trigger("check_node",{node:b,selected:this._data.checkbox.selected,event:c})))):!1},this.uncheck_node=function(b,c){if(this.settings.checkbox.tie_selection)return this.deselect_node(b,!1,c);var d,e,f;if(a.isArray(b)){for(b=b.slice(),d=0,e=b.length;e>d;d++)this.uncheck_node(b[d],c);return!0}return b=this.get_node(b),b&&"#"!==b.id?(f=this.get_node(b,!0),void(b.state.checked&&(b.state.checked=!1,this._data.checkbox.selected=a.vakata.array_remove_item(this._data.checkbox.selected,b.id),f.length&&f.children(".jstree-anchor").removeClass("jstree-checked"),this.trigger("uncheck_node",{node:b,selected:this._data.checkbox.selected,event:c})))):!1},this.check_all=function(){if(this.settings.checkbox.tie_selection)return this.select_all();var a=this._data.checkbox.selected.concat([]),b,c;for(this._data.checkbox.selected=this._model.data["#"].children_d.concat(),b=0,c=this._data.checkbox.selected.length;c>b;b++)this._model.data[this._data.checkbox.selected[b]]&&(this._model.data[this._data.checkbox.selected[b]].state.checked=!0);this.redraw(!0),this.trigger("check_all",{selected:this._data.checkbox.selected})},this.uncheck_all=function(){if(this.settings.checkbox.tie_selection)return this.deselect_all();var a=this._data.checkbox.selected.concat([]),b,c;for(b=0,c=this._data.checkbox.selected.length;c>b;b++)this._model.data[this._data.checkbox.selected[b]]&&(this._model.data[this._data.checkbox.selected[b]].state.checked=!1);this._data.checkbox.selected=[],this.element.find(".jstree-checked").removeClass("jstree-checked"),this.trigger("uncheck_all",{selected:this._data.checkbox.selected,node:a})},this.is_checked=function(a){return this.settings.checkbox.tie_selection?this.is_selected(a):(a=this.get_node(a),a&&"#"!==a.id?a.state.checked:!1)},this.get_checked=function(b){return this.settings.checkbox.tie_selection?this.get_selected(b):b?a.map(this._data.checkbox.selected,a.proxy(function(a){return this.get_node(a)},this)):this._data.checkbox.selected},this.get_top_checked=function(b){if(this.settings.checkbox.tie_selection)return this.get_top_selected(b);var c=this.get_checked(!0),d={},e,f,g,h;for(e=0,f=c.length;f>e;e++)d[c[e].id]=c[e];for(e=0,f=c.length;f>e;e++)for(g=0,h=c[e].children_d.length;h>g;g++)d[c[e].children_d[g]]&&delete d[c[e].children_d[g]];c=[];for(e in d)d.hasOwnProperty(e)&&c.push(e);return b?a.map(c,a.proxy(function(a){return this.get_node(a)},this)):c},this.get_bottom_checked=function(b){if(this.settings.checkbox.tie_selection)return this.get_bottom_selected(b);var c=this.get_checked(!0),d=[],e,f;for(e=0,f=c.length;f>e;e++)c[e].children.length||d.push(c[e].id);return b?a.map(d,a.proxy(function(a){return this.get_node(a)},this)):d},this.load_node=function(b,d){var e,f,g,h,i,j;if(!a.isArray(b)&&!this.settings.checkbox.tie_selection&&(j=this.get_node(b),j&&j.state.loaded))for(e=0,f=j.children_d.length;f>e;e++)this._model.data[j.children_d[e]].state.checked&&(i=!0,this._data.checkbox.selected=a.vakata.array_remove_item(this._data.checkbox.selected,j.children_d[e]));return c.load_node.apply(this,arguments)},this.get_state=function(){var a=c.get_state.apply(this,arguments);return this.settings.checkbox.tie_selection?a:(a.checkbox=this._data.checkbox.selected.slice(),a)},this.set_state=function(b,d){var e=c.set_state.apply(this,arguments);if(e&&b.checkbox){if(!this.settings.checkbox.tie_selection){this.uncheck_all();var f=this;a.each(b.checkbox,function(a,b){f.check_node(b)})}return delete b.checkbox,!1}return e}};var n=null,o,p;a.jstree.defaults.contextmenu={select_node:!0,show_at_node:!0,items:function(b,c){return{create:{separator_before:!1,separator_after:!0,_disabled:!1,label:"Create",action:function(b){var c=a.jstree.reference(b.reference),d=c.get_node(b.reference);c.create_node(d,{},"last",function(a){setTimeout(function(){c.edit(a)},0)})}},rename:{separator_before:!1,separator_after:!1,_disabled:!1,label:"Rename",action:function(b){var c=a.jstree.reference(b.reference),d=c.get_node(b.reference);c.edit(d)}},remove:{separator_before:!1,icon:!1,separator_after:!1,_disabled:!1,label:"Delete",action:function(b){var c=a.jstree.reference(b.reference),d=c.get_node(b.reference);c.delete_node(c.is_selected(d)?c.get_selected():d)}},ccp:{separator_before:!0,icon:!1,separator_after:!1,label:"Edit",action:!1,submenu:{cut:{separator_before:!1,separator_after:!1,label:"Cut",action:function(b){var c=a.jstree.reference(b.reference),d=c.get_node(b.reference);c.cut(c.is_selected(d)?c.get_selected():d)}},copy:{separator_before:!1,icon:!1,separator_after:!1,label:"Copy",action:function(b){var c=a.jstree.reference(b.reference),d=c.get_node(b.reference);c.copy(c.is_selected(d)?c.get_selected():d)}},paste:{separator_before:!1,icon:!1,_disabled:function(b){return!a.jstree.reference(b.reference).can_paste()},separator_after:!1,label:"Paste",action:function(b){var c=a.jstree.reference(b.reference),d=c.get_node(b.reference);c.paste(d)}}}}}}},a.jstree.plugins.contextmenu=function(c,d){this.bind=function(){d.bind.call(this);var b=0;this.element.on("contextmenu.jstree",".jstree-anchor",a.proxy(function(a,c){a.preventDefault(),b=a.ctrlKey?+new Date:0,(c||n)&&(b=+new Date+1e4),n&&clearTimeout(n),this.is_loading(a.currentTarget)||this.show_contextmenu(a.currentTarget,a.pageX,a.pageY,a)},this)).on("click.jstree",".jstree-anchor",a.proxy(function(c){this._data.contextmenu.visible&&(!b||+new Date-b>250)&&a.vakata.context.hide(),b=0},this)).on("touchstart.jstree",".jstree-anchor",function(b){b.originalEvent&&b.originalEvent.changedTouches&&b.originalEvent.changedTouches[0]&&(o=b.pageX,p=b.pageY,n=setTimeout(function(){a(b.currentTarget).trigger("contextmenu",!0)},750))}),a(document).on("context_hide.vakata.jstree",a.proxy(function(){this._data.contextmenu.visible=!1},this))},this.teardown=function(){this._data.contextmenu.visible&&a.vakata.context.hide(),d.teardown.call(this)},this.show_contextmenu=function(c,d,e,f){if(c=this.get_node(c),!c||"#"===c.id)return!1;var g=this.settings.contextmenu,h=this.get_node(c,!0),i=h.children(".jstree-anchor"),j=!1,k=!1;(g.show_at_node||d===b||e===b)&&(j=i.offset(),d=j.left,e=j.top+this._data.core.li_height),this.settings.contextmenu.select_node&&!this.is_selected(c)&&this.activate_node(c,f),k=g.items,a.isFunction(k)&&(k=k.call(this,c,a.proxy(function(a){this._show_contextmenu(c,d,e,a)},this))),a.isPlainObject(k)&&this._show_contextmenu(c,d,e,k)},this._show_contextmenu=function(b,c,d,e){var f=this.get_node(b,!0),g=f.children(".jstree-anchor");a(document).one("context_show.vakata.jstree",a.proxy(function(b,c){var d="jstree-contextmenu jstree-"+this.get_theme()+"-contextmenu";a(c.element).addClass(d)},this)),this._data.contextmenu.visible=!0,a.vakata.context.show(g,{x:c,y:d},e),this.trigger("show_contextmenu",{node:b,x:c,y:d})}},a(function(){a(document).on("touchmove.vakata.jstree",function(a){n&&a.originalEvent&&a.originalEvent.changedTouches&&a.originalEvent.changedTouches[0]&&(Math.abs(o-a.pageX)>50||Math.abs(p-a.pageY)>50)&&clearTimeout(n)}).on("touchend.vakata.jstree",function(a){n&&clearTimeout(n)})}),function(a){var b=!1,c={element:!1,reference:!1,position_x:0,position_y:0,items:[],html:"",is_visible:!1};a.vakata.context={settings:{hide_onmouseleave:0,icons:!0},_trigger:function(b){a(document).triggerHandler("context_"+b+".vakata",{reference:c.reference,element:c.element,position:{x:c.position_x,y:c.position_y}})},_execute:function(b){return b=c.items[b],b&&(!b._disabled||a.isFunction(b._disabled)&&!b._disabled({item:b,reference:c.reference,element:c.element}))&&b.action?b.action.call(null,{item:b,reference:c.reference,element:c.element,position:{x:c.position_x,y:c.position_y}}):!1},_parse:function(b,d){if(!b)return!1;d||(c.html="",c.items=[]);var e="",f=!1,g;return d&&(e+="<ul>"),a.each(b,function(b,d){return d?(c.items.push(d),!f&&d.separator_before&&(e+="<li class='vakata-context-separator'><a href='#' "+(a.vakata.context.settings.icons?"":'style="margin-left:0px;"')+">&#160;</a></li>"),f=!1,e+="<li class='"+(d._class||"")+(d._disabled===!0||a.isFunction(d._disabled)&&d._disabled({item:d,reference:c.reference,element:c.element})?" vakata-contextmenu-disabled ":"")+"' "+(d.shortcut?" data-shortcut='"+d.shortcut+"' ":"")+">",e+="<a href='#' rel='"+(c.items.length-1)+"'>",a.vakata.context.settings.icons&&(e+="<i ",d.icon&&(e+=-1!==d.icon.indexOf("/")||-1!==d.icon.indexOf(".")?" style='background:url(\""+d.icon+"\") center center no-repeat' ":" class='"+d.icon+"' "),e+="></i><span class='vakata-contextmenu-sep'>&#160;</span>"),e+=(a.isFunction(d.label)?d.label({item:b,reference:c.reference,element:c.element}):d.label)+(d.shortcut?' <span class="vakata-contextmenu-shortcut vakata-contextmenu-shortcut-'+d.shortcut+'">'+(d.shortcut_label||"")+"</span>":"")+"</a>",d.submenu&&(g=a.vakata.context._parse(d.submenu,!0),g&&(e+=g)),e+="</li>",void(d.separator_after&&(e+="<li class='vakata-context-separator'><a href='#' "+(a.vakata.context.settings.icons?"":'style="margin-left:0px;"')+">&#160;</a></li>",f=!0))):!0}),e=e.replace(/<li class\='vakata-context-separator'\><\/li\>$/,""),d&&(e+="</ul>"),d||(c.html=e,a.vakata.context._trigger("parse")),e.length>10?e:!1},_show_submenu:function(c){if(c=a(c),c.length&&c.children("ul").length){var d=c.children("ul"),e=c.offset().left+c.outerWidth(),f=c.offset().top,g=d.width(),h=d.height(),i=a(window).width()+a(window).scrollLeft(),j=a(window).height()+a(window).scrollTop();b?c[e-(g+10+c.outerWidth())<0?"addClass":"removeClass"]("vakata-context-left"):c[e+g+10>i?"addClass":"removeClass"]("vakata-context-right"),f+h+10>j&&d.css("bottom","-1px"),d.show()}},show:function(d,e,f){var g,h,i,j,k,l,m,n,o=!0;switch(c.element&&c.element.length&&c.element.width(""),o){case!e&&!d:return!1;case!!e&&!!d:c.reference=d,c.position_x=e.x,c.position_y=e.y;break;case!e&&!!d:c.reference=d,g=d.offset(),c.position_x=g.left+d.outerHeight(),c.position_y=g.top;break;case!!e&&!d:c.position_x=e.x,c.position_y=e.y}d&&!f&&a(d).data("vakata_contextmenu")&&(f=a(d).data("vakata_contextmenu")),a.vakata.context._parse(f)&&c.element.html(c.html),c.items.length&&(c.element.appendTo("body"),h=c.element,i=c.position_x,j=c.position_y,k=h.width(),l=h.height(),m=a(window).width()+a(window).scrollLeft(),n=a(window).height()+a(window).scrollTop(),b&&(i-=h.outerWidth()-a(d).outerWidth(),i<a(window).scrollLeft()+20&&(i=a(window).scrollLeft()+20)),i+k+20>m&&(i=m-(k+20)),j+l+20>n&&(j=n-(l+20)),c.element.css({left:i,top:j}).show().find("a").first().focus().parent().addClass("vakata-context-hover"),c.is_visible=!0,a.vakata.context._trigger("show"))},hide:function(){c.is_visible&&(c.element.hide().find("ul").hide().end().find(":focus").blur().end().detach(),c.is_visible=!1,a.vakata.context._trigger("hide"))}},a(function(){b="rtl"===a("body").css("direction");var d=!1;c.element=a("<ul class='vakata-context'></ul>"),c.element.on("mouseenter","li",function(b){b.stopImmediatePropagation(),a.contains(this,b.relatedTarget)||(d&&clearTimeout(d),c.element.find(".vakata-context-hover").removeClass("vakata-context-hover").end(),a(this).siblings().find("ul").hide().end().end().parentsUntil(".vakata-context","li").addBack().addClass("vakata-context-hover"),a.vakata.context._show_submenu(this))}).on("mouseleave","li",function(b){a.contains(this,b.relatedTarget)||a(this).find(".vakata-context-hover").addBack().removeClass("vakata-context-hover")}).on("mouseleave",function(b){a(this).find(".vakata-context-hover").removeClass("vakata-context-hover"),a.vakata.context.settings.hide_onmouseleave&&(d=setTimeout(function(b){return function(){a.vakata.context.hide()}}(this),a.vakata.context.settings.hide_onmouseleave))}).on("click","a",function(b){b.preventDefault(),a(this).blur().parent().hasClass("vakata-context-disabled")||a.vakata.context._execute(a(this).attr("rel"))===!1||a.vakata.context.hide()}).on("keydown","a",function(b){var d=null;switch(b.which){case 13:case 32:b.type="mouseup",b.preventDefault(),a(b.currentTarget).trigger(b);break;case 37:c.is_visible&&(c.element.find(".vakata-context-hover").last().closest("li").first().find("ul").hide().find(".vakata-context-hover").removeClass("vakata-context-hover").end().end().children("a").focus(),b.stopImmediatePropagation(),b.preventDefault());break;case 38:c.is_visible&&(d=c.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").prevAll("li:not(.vakata-context-separator)").first(),d.length||(d=c.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").last()),d.addClass("vakata-context-hover").children("a").focus(),b.stopImmediatePropagation(),b.preventDefault());break;case 39:c.is_visible&&(c.element.find(".vakata-context-hover").last().children("ul").show().children("li:not(.vakata-context-separator)").removeClass("vakata-context-hover").first().addClass("vakata-context-hover").children("a").focus(),b.stopImmediatePropagation(),b.preventDefault());break;case 40:c.is_visible&&(d=c.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").nextAll("li:not(.vakata-context-separator)").first(),d.length||(d=c.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").first()),d.addClass("vakata-context-hover").children("a").focus(),b.stopImmediatePropagation(),b.preventDefault());break;case 27:a.vakata.context.hide(),b.preventDefault()}}).on("keydown",function(a){a.preventDefault();var b=c.element.find(".vakata-contextmenu-shortcut-"+a.which).parent();b.parent().not(".vakata-context-disabled")&&b.click()}),a(document).on("mousedown.vakata.jstree",function(b){c.is_visible&&!a.contains(c.element[0],b.target)&&a.vakata.context.hide()}).on("context_show.vakata.jstree",function(a,d){c.element.find("li:has(ul)").children("a").addClass("vakata-context-parent"),b&&c.element.addClass("vakata-context-rtl").css("direction","rtl"),c.element.find("ul").hide().end()})})}(a),a.jstree.defaults.dnd={copy:!0,open_timeout:500,is_draggable:!0,check_while_dragging:!0,always_copy:!1,inside_pos:0,drag_selection:!0,touch:!0},a.jstree.plugins.dnd=function(b,c){this.bind=function(){c.bind.call(this),this.element.on("mousedown.jstree touchstart.jstree",".jstree-anchor",a.proxy(function(b){if("touchstart"===b.type&&(!this.settings.dnd.touch||"selected"===this.settings.dnd.touch&&!a(b.currentTarget).hasClass("jstree-clicked")))return!0;var c=this.get_node(b.target),d=this.is_selected(c)&&this.settings.drag_selection?this.get_selected().length:1,e=d>1?d+" "+this.get_string("nodes"):this.get_text(b.currentTarget);return this.settings.core.force_text&&(e=a("<div />").text(e).html()),c&&c.id&&"#"!==c.id&&(1===b.which||"touchstart"===b.type)&&(this.settings.dnd.is_draggable===!0||a.isFunction(this.settings.dnd.is_draggable)&&this.settings.dnd.is_draggable.call(this,d>1?this.get_selected(!0):[c]))?(this.element.trigger("mousedown.jstree"),a.vakata.dnd.start(b,{jstree:!0,origin:this,obj:this.get_node(c,!0),nodes:d>1?this.get_selected():[c.id]},'<div id="jstree-dnd" class="jstree-'+this.get_theme()+" jstree-"+this.get_theme()+"-"+this.get_theme_variant()+" "+(this.settings.core.themes.responsive?" jstree-dnd-responsive":"")+'"><i class="jstree-icon jstree-er"></i>'+e+'<ins class="jstree-copy" style="display:none;">+</ins></div>')):void 0},this))}},a(function(){var b=!1,c=!1,d=!1,e=a('<div id="jstree-marker">&#160;</div>').hide();a(document).on("dnd_start.vakata.jstree",function(a,c){b=!1,c&&c.data&&c.data.jstree&&e.appendTo("body")}).on("dnd_move.vakata.jstree",function(f,g){if(d&&clearTimeout(d),g&&g.data&&g.data.jstree&&(!g.event.target.id||"jstree-marker"!==g.event.target.id)){var h=a.jstree.reference(g.event.target),i=!1,j=!1,k=!1,l,m,n,o,p,q,r,s,t,u,v,w,x,y;if(h&&h._data&&h._data.dnd)if(e.attr("class","jstree-"+h.get_theme()+(h.settings.core.themes.responsive?" jstree-dnd-responsive":"")),g.helper.children().attr("class","jstree-"+h.get_theme()+" jstree-"+h.get_theme()+"-"+h.get_theme_variant()+" "+(h.settings.core.themes.responsive?" jstree-dnd-responsive":"")).find(".jstree-copy").first()[g.data.origin&&(g.data.origin.settings.dnd.always_copy||g.data.origin.settings.dnd.copy&&(g.event.metaKey||g.event.ctrlKey))?"show":"hide"](),g.event.target!==h.element[0]&&g.event.target!==h.get_container_ul()[0]||0!==h.get_container_ul().children().length){if(i=a(g.event.target).closest(".jstree-anchor"),i&&i.length&&i.parent().is(".jstree-closed, .jstree-open, .jstree-leaf")&&(j=i.offset(),k=g.event.pageY-j.top,n=i.height(),q=n/3>k?["b","i","a"]:k>n-n/3?["a","i","b"]:k>n/2?["i","a","b"]:["i","b","a"],a.each(q,function(f,k){switch(k){case"b":l=j.left-6,m=j.top,o=h.get_parent(i),p=i.parent().index();break;case"i":x=h.settings.dnd.inside_pos,y=h.get_node(i.parent()),l=j.left-2,m=j.top+n/2+1,o=y.id,p="first"===x?0:"last"===x?y.children.length:Math.min(x,y.children.length);break;case"a":l=j.left-6,m=j.top+n,o=h.get_parent(i),p=i.parent().index()+1}for(r=!0,s=0,t=g.data.nodes.length;t>s;s++)if(u=g.data.origin&&(g.data.origin.settings.dnd.always_copy||g.data.origin.settings.dnd.copy&&(g.event.metaKey||g.event.ctrlKey))?"copy_node":"move_node",v=p,"move_node"===u&&"a"===k&&g.data.origin&&g.data.origin===h&&o===h.get_parent(g.data.nodes[s])&&(w=h.get_node(o),v>a.inArray(g.data.nodes[s],w.children)&&(v-=1)),r=r&&(h&&h.settings&&h.settings.dnd&&h.settings.dnd.check_while_dragging===!1||h.check(u,g.data.origin&&g.data.origin!==h?g.data.origin.get_node(g.data.nodes[s]):g.data.nodes[s],o,v,{dnd:!0,ref:h.get_node(i.parent()),pos:k,is_multi:g.data.origin&&g.data.origin!==h,is_foreign:!g.data.origin})),!r){h&&h.last_error&&(c=h.last_error());break}return"i"===k&&i.parent().is(".jstree-closed")&&h.settings.dnd.open_timeout&&(d=setTimeout(function(a,b){return function(){a.open_node(b)}}(h,i),h.settings.dnd.open_timeout)),r?(b={ins:h,par:o,pos:"i"!==k||"last"!==x||0!==p||h.is_loaded(y)?p:"last"},e.css({left:l+"px",top:m+"px"}).show(),g.helper.find(".jstree-icon").first().removeClass("jstree-er").addClass("jstree-ok"),c={},q=!0,!1):void 0}),q===!0))return}else{for(r=!0,s=0,t=g.data.nodes.length;t>s;s++)if(r=r&&h.check(g.data.origin&&(g.data.origin.settings.dnd.always_copy||g.data.origin.settings.dnd.copy&&(g.event.metaKey||g.event.ctrlKey))?"copy_node":"move_node",g.data.origin&&g.data.origin!==h?g.data.origin.get_node(g.data.nodes[s]):g.data.nodes[s],"#","last",{dnd:!0,ref:h.get_node("#"),pos:"i",is_multi:g.data.origin&&g.data.origin!==h,is_foreign:!g.data.origin}),!r)break;if(r)return b={ins:h,par:"#",pos:"last"},e.hide(),void g.helper.find(".jstree-icon").first().removeClass("jstree-er").addClass("jstree-ok")}b=!1,g.helper.find(".jstree-icon").removeClass("jstree-ok").addClass("jstree-er"),e.hide()}}).on("dnd_scroll.vakata.jstree",function(a,c){c&&c.data&&c.data.jstree&&(e.hide(),b=!1,c.helper.find(".jstree-icon").first().removeClass("jstree-ok").addClass("jstree-er"))}).on("dnd_stop.vakata.jstree",function(f,g){if(d&&clearTimeout(d),g&&g.data&&g.data.jstree){e.hide().detach();var h,i,j=[];if(b){for(h=0,i=g.data.nodes.length;i>h;h++)j[h]=g.data.origin?g.data.origin.get_node(g.data.nodes[h]):g.data.nodes[h],g.data.origin&&(j[h].instance=g.data.origin);for(b.ins[g.data.origin&&(g.data.origin.settings.dnd.always_copy||g.data.origin.settings.dnd.copy&&(g.event.metaKey||g.event.ctrlKey))?"copy_node":"move_node"](j,b.par,b.pos),h=0,i=j.length;i>h;h++)j[h].instance&&(j[h].instance=null)}else h=a(g.event.target).closest(".jstree"),h.length&&c&&c.error&&"check"===c.error&&(h=h.jstree(!0),h&&h.settings.core.error.call(this,c))}}).on("keyup.jstree keydown.jstree",function(b,c){c=a.vakata.dnd._get(),c&&c.data&&c.data.jstree&&c.helper.find(".jstree-copy").first()[c.data.origin&&(c.data.origin.settings.dnd.always_copy||c.data.origin.settings.dnd.copy&&(b.metaKey||b.ctrlKey))?"show":"hide"]()})}),function(a){var b={element:!1,target:!1,is_down:!1,is_drag:!1,helper:!1,helper_w:0,data:!1,init_x:0,init_y:0,scroll_l:0,scroll_t:0,scroll_e:!1,scroll_i:!1,is_touch:!1};a.vakata.dnd={settings:{scroll_speed:10,scroll_proximity:20,helper_left:5,helper_top:10,threshold:5,threshold_touch:50},_trigger:function(b,c){var d=a.vakata.dnd._get();d.event=c,a(document).triggerHandler("dnd_"+b+".vakata",d)},_get:function(){return{data:b.data,element:b.element,helper:b.helper}},_clean:function(){b.helper&&b.helper.remove(),b.scroll_i&&(clearInterval(b.scroll_i),b.scroll_i=!1),b={element:!1,target:!1,is_down:!1,is_drag:!1,helper:!1,helper_w:0,data:!1,init_x:0,init_y:0,scroll_l:0,scroll_t:0,scroll_e:!1,scroll_i:!1,is_touch:!1},a(document).off("mousemove.vakata.jstree touchmove.vakata.jstree",a.vakata.dnd.drag),a(document).off("mouseup.vakata.jstree touchend.vakata.jstree",a.vakata.dnd.stop)},_scroll:function(c){if(!b.scroll_e||!b.scroll_l&&!b.scroll_t)return b.scroll_i&&(clearInterval(b.scroll_i),b.scroll_i=!1),!1;if(!b.scroll_i)return b.scroll_i=setInterval(a.vakata.dnd._scroll,100),!1;if(c===!0)return!1;var d=b.scroll_e.scrollTop(),e=b.scroll_e.scrollLeft();b.scroll_e.scrollTop(d+b.scroll_t*a.vakata.dnd.settings.scroll_speed),b.scroll_e.scrollLeft(e+b.scroll_l*a.vakata.dnd.settings.scroll_speed),(d!==b.scroll_e.scrollTop()||e!==b.scroll_e.scrollLeft())&&a.vakata.dnd._trigger("scroll",b.scroll_e)},start:function(c,d,e){"touchstart"===c.type&&c.originalEvent&&c.originalEvent.changedTouches&&c.originalEvent.changedTouches[0]&&(c.pageX=c.originalEvent.changedTouches[0].pageX,c.pageY=c.originalEvent.changedTouches[0].pageY,c.target=document.elementFromPoint(c.originalEvent.changedTouches[0].pageX-window.pageXOffset,c.originalEvent.changedTouches[0].pageY-window.pageYOffset)),b.is_drag&&a.vakata.dnd.stop({});try{c.currentTarget.unselectable="on",c.currentTarget.onselectstart=function(){return!1},c.currentTarget.style&&(c.currentTarget.style.MozUserSelect="none")}catch(f){}return b.init_x=c.pageX,b.init_y=c.pageY,b.data=d,b.is_down=!0,b.element=c.currentTarget,b.target=c.target,b.is_touch="touchstart"===c.type,e!==!1&&(b.helper=a("<div id='vakata-dnd'></div>").html(e).css({display:"block",margin:"0",padding:"0",position:"absolute",top:"-2000px",lineHeight:"16px",zIndex:"10000"})),a(document).on("mousemove.vakata.jstree touchmove.vakata.jstree",a.vakata.dnd.drag),a(document).on("mouseup.vakata.jstree touchend.vakata.jstree",a.vakata.dnd.stop),!1
+},drag:function(c){if("touchmove"===c.type&&c.originalEvent&&c.originalEvent.changedTouches&&c.originalEvent.changedTouches[0]&&(c.pageX=c.originalEvent.changedTouches[0].pageX,c.pageY=c.originalEvent.changedTouches[0].pageY,c.target=document.elementFromPoint(c.originalEvent.changedTouches[0].pageX-window.pageXOffset,c.originalEvent.changedTouches[0].pageY-window.pageYOffset)),b.is_down){if(!b.is_drag){if(!(Math.abs(c.pageX-b.init_x)>(b.is_touch?a.vakata.dnd.settings.threshold_touch:a.vakata.dnd.settings.threshold)||Math.abs(c.pageY-b.init_y)>(b.is_touch?a.vakata.dnd.settings.threshold_touch:a.vakata.dnd.settings.threshold)))return;b.helper&&(b.helper.appendTo("body"),b.helper_w=b.helper.outerWidth()),b.is_drag=!0,a.vakata.dnd._trigger("start",c)}var d=!1,e=!1,f=!1,g=!1,h=!1,i=!1,j=!1,k=!1,l=!1,m=!1;return b.scroll_t=0,b.scroll_l=0,b.scroll_e=!1,a(a(c.target).parentsUntil("body").addBack().get().reverse()).filter(function(){return/^auto|scroll$/.test(a(this).css("overflow"))&&(this.scrollHeight>this.offsetHeight||this.scrollWidth>this.offsetWidth)}).each(function(){var d=a(this),e=d.offset();return this.scrollHeight>this.offsetHeight&&(e.top+d.height()-c.pageY<a.vakata.dnd.settings.scroll_proximity&&(b.scroll_t=1),c.pageY-e.top<a.vakata.dnd.settings.scroll_proximity&&(b.scroll_t=-1)),this.scrollWidth>this.offsetWidth&&(e.left+d.width()-c.pageX<a.vakata.dnd.settings.scroll_proximity&&(b.scroll_l=1),c.pageX-e.left<a.vakata.dnd.settings.scroll_proximity&&(b.scroll_l=-1)),b.scroll_t||b.scroll_l?(b.scroll_e=a(this),!1):void 0}),b.scroll_e||(d=a(document),e=a(window),f=d.height(),g=e.height(),h=d.width(),i=e.width(),j=d.scrollTop(),k=d.scrollLeft(),f>g&&c.pageY-j<a.vakata.dnd.settings.scroll_proximity&&(b.scroll_t=-1),f>g&&g-(c.pageY-j)<a.vakata.dnd.settings.scroll_proximity&&(b.scroll_t=1),h>i&&c.pageX-k<a.vakata.dnd.settings.scroll_proximity&&(b.scroll_l=-1),h>i&&i-(c.pageX-k)<a.vakata.dnd.settings.scroll_proximity&&(b.scroll_l=1),(b.scroll_t||b.scroll_l)&&(b.scroll_e=d)),b.scroll_e&&a.vakata.dnd._scroll(!0),b.helper&&(l=parseInt(c.pageY+a.vakata.dnd.settings.helper_top,10),m=parseInt(c.pageX+a.vakata.dnd.settings.helper_left,10),f&&l+25>f&&(l=f-50),h&&m+b.helper_w>h&&(m=h-(b.helper_w+2)),b.helper.css({left:m+"px",top:l+"px"})),a.vakata.dnd._trigger("move",c),!1}},stop:function(c){if("touchend"===c.type&&c.originalEvent&&c.originalEvent.changedTouches&&c.originalEvent.changedTouches[0]&&(c.pageX=c.originalEvent.changedTouches[0].pageX,c.pageY=c.originalEvent.changedTouches[0].pageY,c.target=document.elementFromPoint(c.originalEvent.changedTouches[0].pageX-window.pageXOffset,c.originalEvent.changedTouches[0].pageY-window.pageYOffset)),b.is_drag)a.vakata.dnd._trigger("stop",c);else if("touchend"===c.type&&c.target===b.target){var d=setTimeout(function(){a(c.target).click()},100);a(c.target).one("click",function(){d&&clearTimeout(d)})}return a.vakata.dnd._clean(),!1}}}(a),a.jstree.defaults.search={ajax:!1,fuzzy:!1,case_sensitive:!1,show_only_matches:!1,close_opened_onclear:!0,search_leaves_only:!1,search_callback:!1},a.jstree.plugins.search=function(c,d){this.bind=function(){d.bind.call(this),this._data.search.str="",this._data.search.dom=a(),this._data.search.res=[],this._data.search.opn=[],this._data.search.som=!1,this.element.on("before_open.jstree",a.proxy(function(b,c){var d,e,f,g=this._data.search.res,h=[],i=a();if(g&&g.length&&(this._data.search.dom=a(this.element[0].querySelectorAll("#"+a.map(g,function(b){return-1!=="0123456789".indexOf(b[0])?"\\3"+b[0]+" "+b.substr(1).replace(a.jstree.idregex,"\\$&"):b.replace(a.jstree.idregex,"\\$&")}).join(", #"))),this._data.search.dom.children(".jstree-anchor").addClass("jstree-search"),this._data.search.som&&this._data.search.res.length)){for(d=0,e=g.length;e>d;d++)h=h.concat(this.get_node(g[d]).parents);h=a.vakata.array_remove_item(a.vakata.array_unique(h),"#"),i=h.length?a(this.element[0].querySelectorAll("#"+a.map(h,function(b){return-1!=="0123456789".indexOf(b[0])?"\\3"+b[0]+" "+b.substr(1).replace(a.jstree.idregex,"\\$&"):b.replace(a.jstree.idregex,"\\$&")}).join(", #"))):a(),this.element.find(".jstree-node").hide().filter(".jstree-last").filter(function(){return this.nextSibling}).removeClass("jstree-last"),i=i.add(this._data.search.dom),i.parentsUntil(".jstree").addBack().show().filter(".jstree-children").each(function(){a(this).children(".jstree-node:visible").eq(-1).addClass("jstree-last")})}},this)).on("search.jstree",a.proxy(function(b,c){this._data.search.som&&c.nodes.length&&(this.element.find(".jstree-node").hide().filter(".jstree-last").filter(function(){return this.nextSibling}).removeClass("jstree-last"),c.nodes.parentsUntil(".jstree").addBack().show().filter(".jstree-children").each(function(){a(this).children(".jstree-node:visible").eq(-1).addClass("jstree-last")}))},this)).on("clear_search.jstree",a.proxy(function(a,b){this._data.search.som&&b.nodes.length&&this.element.find(".jstree-node").css("display","").filter(".jstree-last").filter(function(){return this.nextSibling}).removeClass("jstree-last")},this))},this.search=function(c,d,e){if(c===!1||""===a.trim(c.toString()))return this.clear_search();c=c.toString();var f=this.settings.search,g=f.ajax?f.ajax:!1,h=null,i=[],j=[],k,l;return this._data.search.res.length&&this.clear_search(),e===b&&(e=f.show_only_matches),d||g===!1?(this._data.search.str=c,this._data.search.dom=a(),this._data.search.res=[],this._data.search.opn=[],this._data.search.som=e,h=new a.vakata.search(c,!0,{caseSensitive:f.case_sensitive,fuzzy:f.fuzzy}),a.each(this._model.data,function(a,b){b.text&&(f.search_callback&&f.search_callback.call(this,c,b)||!f.search_callback&&h.search(b.text).isMatch)&&(!f.search_leaves_only||b.state.loaded&&0===b.children.length)&&(i.push(a),j=j.concat(b.parents))}),i.length&&(j=a.vakata.array_unique(j),this._search_open(j),this._data.search.dom=a(this.element[0].querySelectorAll("#"+a.map(i,function(b){return-1!=="0123456789".indexOf(b[0])?"\\3"+b[0]+" "+b.substr(1).replace(a.jstree.idregex,"\\$&"):b.replace(a.jstree.idregex,"\\$&")}).join(", #"))),this._data.search.res=i,this._data.search.dom.children(".jstree-anchor").addClass("jstree-search")),void this.trigger("search",{nodes:this._data.search.dom,str:c,res:this._data.search.res,show_only_matches:e})):a.isFunction(g)?g.call(this,c,a.proxy(function(b){b&&b.d&&(b=b.d),this._load_nodes(a.isArray(b)?a.vakata.array_unique(b):[],function(){this.search(c,!0,e)},!0)},this)):(g=a.extend({},g),g.data||(g.data={}),g.data.str=c,a.ajax(g).fail(a.proxy(function(){this._data.core.last_error={error:"ajax",plugin:"search",id:"search_01",reason:"Could not load search parents",data:JSON.stringify(g)},this.settings.core.error.call(this,this._data.core.last_error)},this)).done(a.proxy(function(b){b&&b.d&&(b=b.d),this._load_nodes(a.isArray(b)?a.vakata.array_unique(b):[],function(){this.search(c,!0,e)},!0)},this)))},this.clear_search=function(){this._data.search.dom.children(".jstree-anchor").removeClass("jstree-search"),this.settings.search.close_opened_onclear&&this.close_node(this._data.search.opn,0),this.trigger("clear_search",{nodes:this._data.search.dom,str:this._data.search.str,res:this._data.search.res}),this._data.search.str="",this._data.search.res=[],this._data.search.opn=[],this._data.search.dom=a()},this._search_open=function(b){var c=this;a.each(b.concat([]),function(d,e){if("#"===e)return!0;try{e=a("#"+e.replace(a.jstree.idregex,"\\$&"),c.element)}catch(f){}e&&e.length&&c.is_closed(e)&&(c._data.search.opn.push(e[0].id),c.open_node(e,function(){c._search_open(b)},0))})}},function(a){a.vakata.search=function(a,b,c){c=c||{},c.fuzzy!==!1&&(c.fuzzy=!0),a=c.caseSensitive?a:a.toLowerCase();var d=c.location||0,e=c.distance||100,f=c.threshold||.6,g=a.length,h,i,j,k;return g>32&&(c.fuzzy=!1),c.fuzzy&&(h=1<<g-1,i=function(){var b={},c=0;for(c=0;g>c;c++)b[a.charAt(c)]=0;for(c=0;g>c;c++)b[a.charAt(c)]|=1<<g-c-1;return b}(),j=function(a,b){var c=a/g,f=Math.abs(d-b);return e?c+f/e:f?1:c}),k=function(b){if(b=c.caseSensitive?b:b.toLowerCase(),a===b||-1!==b.indexOf(a))return{isMatch:!0,score:0};if(!c.fuzzy)return{isMatch:!1,score:1};var e,k,l=b.length,m=f,n=b.indexOf(a,d),o,p,q=g+l,r,s,t,u,v,w=1,x=[];for(-1!==n&&(m=Math.min(j(0,n),m),n=b.lastIndexOf(a,d+g),-1!==n&&(m=Math.min(j(0,n),m))),n=-1,e=0;g>e;e++){o=0,p=q;while(p>o)j(e,d+p)<=m?o=p:q=p,p=Math.floor((q-o)/2+o);for(q=p,s=Math.max(1,d-p+1),t=Math.min(d+p,l)+g,u=new Array(t+2),u[t+1]=(1<<e)-1,k=t;k>=s;k--)if(v=i[b.charAt(k-1)],u[k]=0===e?(u[k+1]<<1|1)&v:(u[k+1]<<1|1)&v|((r[k+1]|r[k])<<1|1)|r[k+1],u[k]&h&&(w=j(e,k-1),m>=w)){if(m=w,n=k-1,x.push(n),!(n>d))break;s=Math.max(1,2*d-n)}if(j(e+1,d)>m)break;r=u}return{isMatch:n>=0,score:w}},b===!0?{search:k}:k(b)}}(a),a.jstree.defaults.sort=function(a,b){return this.get_text(a)>this.get_text(b)?1:-1},a.jstree.plugins.sort=function(b,c){this.bind=function(){c.bind.call(this),this.element.on("model.jstree",a.proxy(function(a,b){this.sort(b.parent,!0)},this)).on("rename_node.jstree create_node.jstree",a.proxy(function(a,b){this.sort(b.parent||b.node.parent,!1),this.redraw_node(b.parent||b.node.parent,!0)},this)).on("move_node.jstree copy_node.jstree",a.proxy(function(a,b){this.sort(b.parent,!1),this.redraw_node(b.parent,!0)},this))},this.sort=function(b,c){var d,e;if(b=this.get_node(b),b&&b.children&&b.children.length&&(b.children.sort(a.proxy(this.settings.sort,this)),c))for(d=0,e=b.children_d.length;e>d;d++)this.sort(b.children_d[d],!1)}};var q=!1;a.jstree.defaults.state={key:"jstree",events:"changed.jstree open_node.jstree close_node.jstree check_node.jstree uncheck_node.jstree",ttl:!1,filter:!1},a.jstree.plugins.state=function(b,c){this.bind=function(){c.bind.call(this);var b=a.proxy(function(){this.element.on(this.settings.state.events,a.proxy(function(){q&&clearTimeout(q),q=setTimeout(a.proxy(function(){this.save_state()},this),100)},this)),this.trigger("state_ready")},this);this.element.on("ready.jstree",a.proxy(function(a,c){this.element.one("restore_state.jstree",b),this.restore_state()||b()},this))},this.save_state=function(){var b={state:this.get_state(),ttl:this.settings.state.ttl,sec:+new Date};a.vakata.storage.set(this.settings.state.key,JSON.stringify(b))},this.restore_state=function(){var b=a.vakata.storage.get(this.settings.state.key);if(b)try{b=JSON.parse(b)}catch(c){return!1}return b&&b.ttl&&b.sec&&+new Date-b.sec>b.ttl?!1:(b&&b.state&&(b=b.state),b&&a.isFunction(this.settings.state.filter)&&(b=this.settings.state.filter.call(this,b)),b?(this.element.one("set_state.jstree",function(c,d){d.instance.trigger("restore_state",{state:a.extend(!0,{},b)})}),this.set_state(b),!0):!1)},this.clear_state=function(){return a.vakata.storage.del(this.settings.state.key)}},function(a,b){a.vakata.storage={set:function(a,b){return window.localStorage.setItem(a,b)},get:function(a){return window.localStorage.getItem(a)},del:function(a){return window.localStorage.removeItem(a)}}}(a),a.jstree.defaults.types={"#":{},"default":{}},a.jstree.plugins.types=function(c,d){this.init=function(a,c){var e,f;if(c&&c.types&&c.types["default"])for(e in c.types)if("default"!==e&&"#"!==e&&c.types.hasOwnProperty(e))for(f in c.types["default"])c.types["default"].hasOwnProperty(f)&&c.types[e][f]===b&&(c.types[e][f]=c.types["default"][f]);d.init.call(this,a,c),this._model.data["#"].type="#"},this.refresh=function(a,b){d.refresh.call(this,a,b),this._model.data["#"].type="#"},this.bind=function(){this.element.on("model.jstree",a.proxy(function(a,c){var d=this._model.data,e=c.nodes,f=this.settings.types,g,h,i="default";for(g=0,h=e.length;h>g;g++)i="default",d[e[g]].original&&d[e[g]].original.type&&f[d[e[g]].original.type]&&(i=d[e[g]].original.type),d[e[g]].data&&d[e[g]].data.jstree&&d[e[g]].data.jstree.type&&f[d[e[g]].data.jstree.type]&&(i=d[e[g]].data.jstree.type),d[e[g]].type=i,d[e[g]].icon===!0&&f[i].icon!==b&&(d[e[g]].icon=f[i].icon);d["#"].type="#"},this)),d.bind.call(this)},this.get_json=function(b,c,e){var f,g,h=this._model.data,i=c?a.extend(!0,{},c,{no_id:!1}):{},j=d.get_json.call(this,b,i,e);if(j===!1)return!1;if(a.isArray(j))for(f=0,g=j.length;g>f;f++)j[f].type=j[f].id&&h[j[f].id]&&h[j[f].id].type?h[j[f].id].type:"default",c&&c.no_id&&(delete j[f].id,j[f].li_attr&&j[f].li_attr.id&&delete j[f].li_attr.id,j[f].a_attr&&j[f].a_attr.id&&delete j[f].a_attr.id);else j.type=j.id&&h[j.id]&&h[j.id].type?h[j.id].type:"default",c&&c.no_id&&(j=this._delete_ids(j));return j},this._delete_ids=function(b){if(a.isArray(b)){for(var c=0,d=b.length;d>c;c++)b[c]=this._delete_ids(b[c]);return b}return delete b.id,b.li_attr&&b.li_attr.id&&delete b.li_attr.id,b.a_attr&&b.a_attr.id&&delete b.a_attr.id,b.children&&a.isArray(b.children)&&(b.children=this._delete_ids(b.children)),b},this.check=function(c,e,f,g,h){if(d.check.call(this,c,e,f,g,h)===!1)return!1;e=e&&e.id?e:this.get_node(e),f=f&&f.id?f:this.get_node(f);var i=e&&e.id?a.jstree.reference(e.id):null,j,k,l,m;switch(i=i&&i._model&&i._model.data?i._model.data:null,c){case"create_node":case"move_node":case"copy_node":if("move_node"!==c||-1===a.inArray(e.id,f.children)){if(j=this.get_rules(f),j.max_children!==b&&-1!==j.max_children&&j.max_children===f.children.length)return this._data.core.last_error={error:"check",plugin:"types",id:"types_01",reason:"max_children prevents function: "+c,data:JSON.stringify({chk:c,pos:g,obj:e&&e.id?e.id:!1,par:f&&f.id?f.id:!1})},!1;if(j.valid_children!==b&&-1!==j.valid_children&&-1===a.inArray(e.type||"default",j.valid_children))return this._data.core.last_error={error:"check",plugin:"types",id:"types_02",reason:"valid_children prevents function: "+c,data:JSON.stringify({chk:c,pos:g,obj:e&&e.id?e.id:!1,par:f&&f.id?f.id:!1})},!1;if(i&&e.children_d&&e.parents){for(k=0,l=0,m=e.children_d.length;m>l;l++)k=Math.max(k,i[e.children_d[l]].parents.length);k=k-e.parents.length+1}(0>=k||k===b)&&(k=1);do{if(j.max_depth!==b&&-1!==j.max_depth&&j.max_depth<k)return this._data.core.last_error={error:"check",plugin:"types",id:"types_03",reason:"max_depth prevents function: "+c,data:JSON.stringify({chk:c,pos:g,obj:e&&e.id?e.id:!1,par:f&&f.id?f.id:!1})},!1;f=this.get_node(f.parent),j=this.get_rules(f),k++}while(f)}}return!0},this.get_rules=function(a){if(a=this.get_node(a),!a)return!1;var c=this.get_type(a,!0);return c.max_depth===b&&(c.max_depth=-1),c.max_children===b&&(c.max_children=-1),c.valid_children===b&&(c.valid_children=-1),c},this.get_type=function(b,c){return b=this.get_node(b),b?c?a.extend({type:b.type},this.settings.types[b.type]):b.type:!1},this.set_type=function(c,d){var e,f,g,h,i;if(a.isArray(c)){for(c=c.slice(),f=0,g=c.length;g>f;f++)this.set_type(c[f],d);return!0}return e=this.settings.types,c=this.get_node(c),e[d]&&c?(h=c.type,i=this.get_icon(c),c.type=d,(i===!0||e[h]&&e[h].icon!==b&&i===e[h].icon)&&this.set_icon(c,e[d].icon!==b?e[d].icon:!0),!0):!1}},a.jstree.defaults.unique={case_sensitive:!1,duplicate:function(a,b){return a+" ("+b+")"}},a.jstree.plugins.unique=function(c,d){this.check=function(b,c,e,f,g){if(d.check.call(this,b,c,e,f,g)===!1)return!1;if(c=c&&c.id?c:this.get_node(c),e=e&&e.id?e:this.get_node(e),!e||!e.children)return!0;var h="rename_node"===b?f:c.text,i=[],j=this.settings.unique.case_sensitive,k=this._model.data,l,m;for(l=0,m=e.children.length;m>l;l++)i.push(j?k[e.children[l]].text:k[e.children[l]].text.toLowerCase());switch(j||(h=h.toLowerCase()),b){case"delete_node":return!0;case"rename_node":return l=-1===a.inArray(h,i)||c.text&&c.text[j?"toString":"toLowerCase"]()===h,l||(this._data.core.last_error={error:"check",plugin:"unique",id:"unique_01",reason:"Child with name "+h+" already exists. Preventing: "+b,data:JSON.stringify({chk:b,pos:f,obj:c&&c.id?c.id:!1,par:e&&e.id?e.id:!1})}),l;case"create_node":return l=-1===a.inArray(h,i),l||(this._data.core.last_error={error:"check",plugin:"unique",id:"unique_04",reason:"Child with name "+h+" already exists. Preventing: "+b,data:JSON.stringify({chk:b,pos:f,obj:c&&c.id?c.id:!1,par:e&&e.id?e.id:!1})}),l;case"copy_node":return l=-1===a.inArray(h,i),l||(this._data.core.last_error={error:"check",plugin:"unique",id:"unique_02",reason:"Child with name "+h+" already exists. Preventing: "+b,data:JSON.stringify({chk:b,pos:f,obj:c&&c.id?c.id:!1,par:e&&e.id?e.id:!1})}),l;case"move_node":return l=c.parent===e.id||-1===a.inArray(h,i),l||(this._data.core.last_error={error:"check",plugin:"unique",id:"unique_03",reason:"Child with name "+h+" already exists. Preventing: "+b,data:JSON.stringify({chk:b,pos:f,obj:c&&c.id?c.id:!1,par:e&&e.id?e.id:!1})}),l}return!0},this.create_node=function(c,e,f,g,h){if(!e||e.text===b){if(null===c&&(c="#"),c=this.get_node(c),!c)return d.create_node.call(this,c,e,f,g,h);if(f=f===b?"last":f,!f.toString().match(/^(before|after)$/)&&!h&&!this.is_loaded(c))return d.create_node.call(this,c,e,f,g,h);e||(e={});var i,j,k,l,m,n=this._model.data,o=this.settings.unique.case_sensitive,p=this.settings.unique.duplicate;for(j=i=this.get_string("New node"),k=[],l=0,m=c.children.length;m>l;l++)k.push(o?n[c.children[l]].text:n[c.children[l]].text.toLowerCase());l=1;while(-1!==a.inArray(o?j:j.toLowerCase(),k))j=p.call(this,i,++l).toString();e.text=j}return d.create_node.call(this,c,e,f,g,h)}};var r=document.createElement("DIV");r.setAttribute("unselectable","on"),r.setAttribute("role","presentation"),r.className="jstree-wholerow",r.innerHTML="&#160;",a.jstree.plugins.wholerow=function(b,c){this.bind=function(){c.bind.call(this),this.element.on("ready.jstree set_state.jstree",a.proxy(function(){this.hide_dots()},this)).on("init.jstree loading.jstree ready.jstree",a.proxy(function(){this.get_container_ul().addClass("jstree-wholerow-ul")},this)).on("deselect_all.jstree",a.proxy(function(a,b){this.element.find(".jstree-wholerow-clicked").removeClass("jstree-wholerow-clicked")},this)).on("changed.jstree",a.proxy(function(a,b){this.element.find(".jstree-wholerow-clicked").removeClass("jstree-wholerow-clicked");var c=!1,d,e;for(d=0,e=b.selected.length;e>d;d++)c=this.get_node(b.selected[d],!0),c&&c.length&&c.children(".jstree-wholerow").addClass("jstree-wholerow-clicked")},this)).on("open_node.jstree",a.proxy(function(a,b){this.get_node(b.node,!0).find(".jstree-clicked").parent().children(".jstree-wholerow").addClass("jstree-wholerow-clicked")},this)).on("hover_node.jstree dehover_node.jstree",a.proxy(function(a,b){"hover_node"===a.type&&this.is_disabled(b.node)||this.get_node(b.node,!0).children(".jstree-wholerow")["hover_node"===a.type?"addClass":"removeClass"]("jstree-wholerow-hovered")},this)).on("contextmenu.jstree",".jstree-wholerow",a.proxy(function(b){b.preventDefault();var c=a.Event("contextmenu",{metaKey:b.metaKey,ctrlKey:b.ctrlKey,altKey:b.altKey,shiftKey:b.shiftKey,pageX:b.pageX,pageY:b.pageY});a(b.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(c)},this)).on("click.jstree",".jstree-wholerow",function(b){b.stopImmediatePropagation();var c=a.Event("click",{metaKey:b.metaKey,ctrlKey:b.ctrlKey,altKey:b.altKey,shiftKey:b.shiftKey});a(b.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(c).focus()}).on("click.jstree",".jstree-leaf > .jstree-ocl",a.proxy(function(b){b.stopImmediatePropagation();var c=a.Event("click",{metaKey:b.metaKey,ctrlKey:b.ctrlKey,altKey:b.altKey,shiftKey:b.shiftKey});a(b.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(c).focus()},this)).on("mouseover.jstree",".jstree-wholerow, .jstree-icon",a.proxy(function(a){return a.stopImmediatePropagation(),this.is_disabled(a.currentTarget)||this.hover_node(a.currentTarget),!1},this)).on("mouseleave.jstree",".jstree-node",a.proxy(function(a){this.dehover_node(a.currentTarget)},this))},this.teardown=function(){this.settings.wholerow&&this.element.find(".jstree-wholerow").remove(),c.teardown.call(this)},this.redraw_node=function(b,d,e,f){if(b=c.redraw_node.apply(this,arguments)){var g=r.cloneNode(!0);-1!==a.inArray(b.id,this._data.core.selected)&&(g.className+=" jstree-wholerow-clicked"),this._data.core.focused&&this._data.core.focused===b.id&&(g.className+=" jstree-wholerow-hovered"),b.insertBefore(g,b.childNodes[0])}return b}},function(a){if(document.registerElement&&Object&&Object.create){var b=Object.create(HTMLElement.prototype);b.createdCallback=function(){var b={core:{},plugins:[]},c;for(c in a.jstree.plugins)a.jstree.plugins.hasOwnProperty(c)&&this.attributes[c]&&(b.plugins.push(c),this.getAttribute(c)&&JSON.parse(this.getAttribute(c))&&(b[c]=JSON.parse(this.getAttribute(c))));for(c in a.jstree.defaults.core)a.jstree.defaults.core.hasOwnProperty(c)&&this.attributes[c]&&(b.core[c]=JSON.parse(this.getAttribute(c))||this.getAttribute(c));jQuery(this).jstree(b)};try{document.registerElement("vakata-jstree",{prototype:b})}catch(c){}}}(jQuery)}});
\ No newline at end of file
diff --git a/htdocs/Libs/jsTree/themes/default-dark/32px.png b/htdocs/Libs/jsTree/themes/default-dark/32px.png
new file mode 100644
index 0000000..d6fd721
--- /dev/null
+++ b/htdocs/Libs/jsTree/themes/default-dark/32px.png
Binary files differ
diff --git a/htdocs/Libs/jsTree/themes/default-dark/40px.png b/htdocs/Libs/jsTree/themes/default-dark/40px.png
new file mode 100644
index 0000000..4fc88e4
--- /dev/null
+++ b/htdocs/Libs/jsTree/themes/default-dark/40px.png
Binary files differ
diff --git a/htdocs/Libs/jsTree/themes/default-dark/style.css b/htdocs/Libs/jsTree/themes/default-dark/style.css
new file mode 100644
index 0000000..61b1417
--- /dev/null
+++ b/htdocs/Libs/jsTree/themes/default-dark/style.css
@@ -0,0 +1,1094 @@
+/* jsTree default dark theme */
+.jstree-node,
+.jstree-children,
+.jstree-container-ul {
+  display: block;
+  margin: 0;
+  padding: 0;
+  list-style-type: none;
+  list-style-image: none;
+}
+.jstree-node {
+  white-space: nowrap;
+}
+.jstree-anchor {
+  display: inline-block;
+  color: black;
+  white-space: nowrap;
+  padding: 0 4px 0 1px;
+  margin: 0;
+  vertical-align: top;
+}
+.jstree-anchor:focus {
+  outline: 0;
+}
+.jstree-anchor,
+.jstree-anchor:link,
+.jstree-anchor:visited,
+.jstree-anchor:hover,
+.jstree-anchor:active {
+  text-decoration: none;
+  color: inherit;
+}
+.jstree-icon {
+  display: inline-block;
+  text-decoration: none;
+  margin: 0;
+  padding: 0;
+  vertical-align: top;
+  text-align: center;
+}
+.jstree-icon:empty {
+  display: inline-block;
+  text-decoration: none;
+  margin: 0;
+  padding: 0;
+  vertical-align: top;
+  text-align: center;
+}
+.jstree-ocl {
+  cursor: pointer;
+}
+.jstree-leaf > .jstree-ocl {
+  cursor: default;
+}
+.jstree .jstree-open > .jstree-children {
+  display: block;
+}
+.jstree .jstree-closed > .jstree-children,
+.jstree .jstree-leaf > .jstree-children {
+  display: none;
+}
+.jstree-anchor > .jstree-themeicon {
+  margin-right: 2px;
+}
+.jstree-no-icons .jstree-themeicon,
+.jstree-anchor > .jstree-themeicon-hidden {
+  display: none;
+}
+.jstree-rtl .jstree-anchor {
+  padding: 0 1px 0 4px;
+}
+.jstree-rtl .jstree-anchor > .jstree-themeicon {
+  margin-left: 2px;
+  margin-right: 0;
+}
+.jstree-rtl .jstree-node {
+  margin-left: 0;
+}
+.jstree-rtl .jstree-container-ul > .jstree-node {
+  margin-right: 0;
+}
+.jstree-wholerow-ul {
+  position: relative;
+  display: inline-block;
+  min-width: 100%;
+}
+.jstree-wholerow-ul .jstree-leaf > .jstree-ocl {
+  cursor: pointer;
+}
+.jstree-wholerow-ul .jstree-anchor,
+.jstree-wholerow-ul .jstree-icon {
+  position: relative;
+}
+.jstree-wholerow-ul .jstree-wholerow {
+  width: 100%;
+  cursor: pointer;
+  position: absolute;
+  left: 0;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+.vakata-context {
+  display: none;
+}
+.vakata-context,
+.vakata-context ul {
+  margin: 0;
+  padding: 2px;
+  position: absolute;
+  background: #f5f5f5;
+  border: 1px solid #979797;
+  -moz-box-shadow: 5px 5px 4px -4px #666666;
+  -webkit-box-shadow: 2px 2px 2px #999999;
+  box-shadow: 2px 2px 2px #999999;
+}
+.vakata-context ul {
+  list-style: none;
+  left: 100%;
+  margin-top: -2.7em;
+  margin-left: -4px;
+}
+.vakata-context .vakata-context-right ul {
+  left: auto;
+  right: 100%;
+  margin-left: auto;
+  margin-right: -4px;
+}
+.vakata-context li {
+  list-style: none;
+  display: inline;
+}
+.vakata-context li > a {
+  display: block;
+  padding: 0 2em 0 2em;
+  text-decoration: none;
+  width: auto;
+  color: black;
+  white-space: nowrap;
+  line-height: 2.4em;
+  -moz-text-shadow: 1px 1px 0 white;
+  -webkit-text-shadow: 1px 1px 0 white;
+  text-shadow: 1px 1px 0 white;
+  -moz-border-radius: 1px;
+  -webkit-border-radius: 1px;
+  border-radius: 1px;
+}
+.vakata-context li > a:hover {
+  position: relative;
+  background-color: #e8eff7;
+  -moz-box-shadow: 0 0 2px #0a6aa1;
+  -webkit-box-shadow: 0 0 2px #0a6aa1;
+  box-shadow: 0 0 2px #0a6aa1;
+}
+.vakata-context li > a.vakata-context-parent {
+  background-image: url("data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAIORI4JlrqN1oMSnmmZDQUAOw==");
+  background-position: right center;
+  background-repeat: no-repeat;
+}
+.vakata-context li > a:focus {
+  outline: 0;
+}
+.vakata-context .vakata-context-hover > a {
+  position: relative;
+  background-color: #e8eff7;
+  -moz-box-shadow: 0 0 2px #0a6aa1;
+  -webkit-box-shadow: 0 0 2px #0a6aa1;
+  box-shadow: 0 0 2px #0a6aa1;
+}
+.vakata-context .vakata-context-separator > a,
+.vakata-context .vakata-context-separator > a:hover {
+  background: white;
+  border: 0;
+  border-top: 1px solid #e2e3e3;
+  height: 1px;
+  min-height: 1px;
+  max-height: 1px;
+  padding: 0;
+  margin: 0 0 0 2.4em;
+  border-left: 1px solid #e0e0e0;
+  -moz-text-shadow: 0 0 0 transparent;
+  -webkit-text-shadow: 0 0 0 transparent;
+  text-shadow: 0 0 0 transparent;
+  -moz-box-shadow: 0 0 0 transparent;
+  -webkit-box-shadow: 0 0 0 transparent;
+  box-shadow: 0 0 0 transparent;
+  -moz-border-radius: 0;
+  -webkit-border-radius: 0;
+  border-radius: 0;
+}
+.vakata-context .vakata-contextmenu-disabled a,
+.vakata-context .vakata-contextmenu-disabled a:hover {
+  color: silver;
+  background-color: transparent;
+  border: 0;
+  box-shadow: 0 0 0;
+}
+.vakata-context li > a > i {
+  text-decoration: none;
+  display: inline-block;
+  width: 2.4em;
+  height: 2.4em;
+  background: transparent;
+  margin: 0 0 0 -2em;
+  vertical-align: top;
+  text-align: center;
+  line-height: 2.4em;
+}
+.vakata-context li > a > i:empty {
+  width: 2.4em;
+  line-height: 2.4em;
+}
+.vakata-context li > a .vakata-contextmenu-sep {
+  display: inline-block;
+  width: 1px;
+  height: 2.4em;
+  background: white;
+  margin: 0 0.5em 0 0;
+  border-left: 1px solid #e2e3e3;
+}
+.vakata-context .vakata-contextmenu-shortcut {
+  font-size: 0.8em;
+  color: silver;
+  opacity: 0.5;
+  display: none;
+}
+.vakata-context-rtl ul {
+  left: auto;
+  right: 100%;
+  margin-left: auto;
+  margin-right: -4px;
+}
+.vakata-context-rtl li > a.vakata-context-parent {
+  background-image: url("data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAINjI+AC7rWHIsPtmoxLAA7");
+  background-position: left center;
+  background-repeat: no-repeat;
+}
+.vakata-context-rtl .vakata-context-separator > a {
+  margin: 0 2.4em 0 0;
+  border-left: 0;
+  border-right: 1px solid #e2e3e3;
+}
+.vakata-context-rtl .vakata-context-left ul {
+  right: auto;
+  left: 100%;
+  margin-left: -4px;
+  margin-right: auto;
+}
+.vakata-context-rtl li > a > i {
+  margin: 0 -2em 0 0;
+}
+.vakata-context-rtl li > a .vakata-contextmenu-sep {
+  margin: 0 0 0 0.5em;
+  border-left-color: white;
+  background: #e2e3e3;
+}
+#jstree-marker {
+  position: absolute;
+  top: 0;
+  left: 0;
+  margin: -5px 0 0 0;
+  padding: 0;
+  border-right: 0;
+  border-top: 5px solid transparent;
+  border-bottom: 5px solid transparent;
+  border-left: 5px solid;
+  width: 0;
+  height: 0;
+  font-size: 0;
+  line-height: 0;
+}
+#jstree-dnd {
+  line-height: 16px;
+  margin: 0;
+  padding: 4px;
+}
+#jstree-dnd .jstree-icon,
+#jstree-dnd .jstree-copy {
+  display: inline-block;
+  text-decoration: none;
+  margin: 0 2px 0 0;
+  padding: 0;
+  width: 16px;
+  height: 16px;
+}
+#jstree-dnd .jstree-ok {
+  background: green;
+}
+#jstree-dnd .jstree-er {
+  background: red;
+}
+#jstree-dnd .jstree-copy {
+  margin: 0 2px 0 2px;
+}
+.jstree-default-dark .jstree-node,
+.jstree-default-dark .jstree-icon {
+  background-repeat: no-repeat;
+  background-color: transparent;
+}
+.jstree-default-dark .jstree-anchor,
+.jstree-default-dark .jstree-wholerow {
+  transition: background-color 0.15s, box-shadow 0.15s;
+}
+.jstree-default-dark .jstree-hovered {
+  background: #555555;
+  border-radius: 2px;
+  box-shadow: inset 0 0 1px #555555;
+}
+.jstree-default-dark .jstree-clicked {
+  background: #5fa2db;
+  border-radius: 2px;
+  box-shadow: inset 0 0 1px #666666;
+}
+.jstree-default-dark .jstree-no-icons .jstree-anchor > .jstree-themeicon {
+  display: none;
+}
+.jstree-default-dark .jstree-disabled {
+  background: transparent;
+  color: #666666;
+}
+.jstree-default-dark .jstree-disabled.jstree-hovered {
+  background: transparent;
+  box-shadow: none;
+}
+.jstree-default-dark .jstree-disabled.jstree-clicked {
+  background: #333333;
+}
+.jstree-default-dark .jstree-disabled > .jstree-icon {
+  opacity: 0.8;
+  filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'jstree-grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#jstree-grayscale");
+  /* Firefox 10+ */
+  filter: gray;
+  /* IE6-9 */
+  -webkit-filter: grayscale(100%);
+  /* Chrome 19+ & Safari 6+ */
+}
+.jstree-default-dark .jstree-search {
+  font-style: italic;
+  color: #ffffff;
+  font-weight: bold;
+}
+.jstree-default-dark .jstree-no-checkboxes .jstree-checkbox {
+  display: none !important;
+}
+.jstree-default-dark.jstree-checkbox-no-clicked .jstree-clicked {
+  background: transparent;
+  box-shadow: none;
+}
+.jstree-default-dark.jstree-checkbox-no-clicked .jstree-clicked.jstree-hovered {
+  background: #555555;
+}
+.jstree-default-dark.jstree-checkbox-no-clicked > .jstree-wholerow-ul .jstree-wholerow-clicked {
+  background: transparent;
+}
+.jstree-default-dark.jstree-checkbox-no-clicked > .jstree-wholerow-ul .jstree-wholerow-clicked.jstree-wholerow-hovered {
+  background: #555555;
+}
+.jstree-default-dark > .jstree-striped {
+  background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAMAAAB/qqA+AAAABlBMVEUAAAAAAAClZ7nPAAAAAnRSTlMNAMM9s3UAAAAXSURBVHjajcEBAQAAAIKg/H/aCQZ70AUBjAATb6YPDgAAAABJRU5ErkJggg==") left top repeat;
+}
+.jstree-default-dark > .jstree-wholerow-ul .jstree-hovered,
+.jstree-default-dark > .jstree-wholerow-ul .jstree-clicked {
+  background: transparent;
+  box-shadow: none;
+  border-radius: 0;
+}
+.jstree-default-dark .jstree-wholerow {
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+}
+.jstree-default-dark .jstree-wholerow-hovered {
+  background: #555555;
+}
+.jstree-default-dark .jstree-wholerow-clicked {
+  background: #5fa2db;
+  background: -moz-linear-gradient(top, #5fa2db 0%, #5fa2db 100%);
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5fa2db), color-stop(100%, #5fa2db));
+  background: -webkit-linear-gradient(top, #5fa2db 0%, #5fa2db 100%);
+  background: -o-linear-gradient(top, #5fa2db 0%, #5fa2db 100%);
+  background: -ms-linear-gradient(top, #5fa2db 0%, #5fa2db 100%);
+  background: linear-gradient(to bottom, #5fa2db 0%, #5fa2db 100%);
+  /*filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='@color1', endColorstr='@color2',GradientType=0 );*/
+}
+.jstree-default-dark .jstree-node {
+  min-height: 24px;
+  line-height: 24px;
+  margin-left: 24px;
+  min-width: 24px;
+}
+.jstree-default-dark .jstree-anchor {
+  line-height: 24px;
+  height: 24px;
+}
+.jstree-default-dark .jstree-icon {
+  width: 24px;
+  height: 24px;
+  line-height: 24px;
+}
+.jstree-default-dark .jstree-icon:empty {
+  width: 24px;
+  height: 24px;
+  line-height: 24px;
+}
+.jstree-default-dark.jstree-rtl .jstree-node {
+  margin-right: 24px;
+}
+.jstree-default-dark .jstree-wholerow {
+  height: 24px;
+}
+.jstree-default-dark .jstree-node,
+.jstree-default-dark .jstree-icon {
+  background-image: url("32px.png");
+}
+.jstree-default-dark .jstree-node {
+  background-position: -292px -4px;
+  background-repeat: repeat-y;
+}
+.jstree-default-dark .jstree-last {
+  background: transparent;
+}
+.jstree-default-dark .jstree-open > .jstree-ocl {
+  background-position: -132px -4px;
+}
+.jstree-default-dark .jstree-closed > .jstree-ocl {
+  background-position: -100px -4px;
+}
+.jstree-default-dark .jstree-leaf > .jstree-ocl {
+  background-position: -68px -4px;
+}
+.jstree-default-dark .jstree-themeicon {
+  background-position: -260px -4px;
+}
+.jstree-default-dark > .jstree-no-dots .jstree-node,
+.jstree-default-dark > .jstree-no-dots .jstree-leaf > .jstree-ocl {
+  background: transparent;
+}
+.jstree-default-dark > .jstree-no-dots .jstree-open > .jstree-ocl {
+  background-position: -36px -4px;
+}
+.jstree-default-dark > .jstree-no-dots .jstree-closed > .jstree-ocl {
+  background-position: -4px -4px;
+}
+.jstree-default-dark .jstree-disabled {
+  background: transparent;
+}
+.jstree-default-dark .jstree-disabled.jstree-hovered {
+  background: transparent;
+}
+.jstree-default-dark .jstree-disabled.jstree-clicked {
+  background: #efefef;
+}
+.jstree-default-dark .jstree-checkbox {
+  background-position: -164px -4px;
+}
+.jstree-default-dark .jstree-checkbox:hover {
+  background-position: -164px -36px;
+}
+.jstree-default-dark.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox,
+.jstree-default-dark .jstree-checked > .jstree-checkbox {
+  background-position: -228px -4px;
+}
+.jstree-default-dark.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover,
+.jstree-default-dark .jstree-checked > .jstree-checkbox:hover {
+  background-position: -228px -36px;
+}
+.jstree-default-dark .jstree-anchor > .jstree-undetermined {
+  background-position: -196px -4px;
+}
+.jstree-default-dark .jstree-anchor > .jstree-undetermined:hover {
+  background-position: -196px -36px;
+}
+.jstree-default-dark > .jstree-striped {
+  background-size: auto 48px;
+}
+.jstree-default-dark.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==");
+  background-position: 100% 1px;
+  background-repeat: repeat-y;
+}
+.jstree-default-dark.jstree-rtl .jstree-last {
+  background: transparent;
+}
+.jstree-default-dark.jstree-rtl .jstree-open > .jstree-ocl {
+  background-position: -132px -36px;
+}
+.jstree-default-dark.jstree-rtl .jstree-closed > .jstree-ocl {
+  background-position: -100px -36px;
+}
+.jstree-default-dark.jstree-rtl .jstree-leaf > .jstree-ocl {
+  background-position: -68px -36px;
+}
+.jstree-default-dark.jstree-rtl > .jstree-no-dots .jstree-node,
+.jstree-default-dark.jstree-rtl > .jstree-no-dots .jstree-leaf > .jstree-ocl {
+  background: transparent;
+}
+.jstree-default-dark.jstree-rtl > .jstree-no-dots .jstree-open > .jstree-ocl {
+  background-position: -36px -36px;
+}
+.jstree-default-dark.jstree-rtl > .jstree-no-dots .jstree-closed > .jstree-ocl {
+  background-position: -4px -36px;
+}
+.jstree-default-dark .jstree-themeicon-custom {
+  background-color: transparent;
+  background-image: none;
+  background-position: 0 0;
+}
+.jstree-default-dark > .jstree-container-ul .jstree-loading > .jstree-ocl {
+  background: url("throbber.gif") center center no-repeat;
+}
+.jstree-default-dark .jstree-file {
+  background: url("32px.png") -100px -68px no-repeat;
+}
+.jstree-default-dark .jstree-folder {
+  background: url("32px.png") -260px -4px no-repeat;
+}
+.jstree-default-dark > .jstree-container-ul > .jstree-node {
+  margin-left: 0;
+  margin-right: 0;
+}
+#jstree-dnd.jstree-default-dark {
+  line-height: 24px;
+  padding: 0 4px;
+}
+#jstree-dnd.jstree-default-dark .jstree-ok,
+#jstree-dnd.jstree-default-dark .jstree-er {
+  background-image: url("32px.png");
+  background-repeat: no-repeat;
+  background-color: transparent;
+}
+#jstree-dnd.jstree-default-dark i {
+  background: transparent;
+  width: 24px;
+  height: 24px;
+  line-height: 24px;
+}
+#jstree-dnd.jstree-default-dark .jstree-ok {
+  background-position: -4px -68px;
+}
+#jstree-dnd.jstree-default-dark .jstree-er {
+  background-position: -36px -68px;
+}
+.jstree-default-dark.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==");
+}
+.jstree-default-dark.jstree-rtl .jstree-last {
+  background: transparent;
+}
+.jstree-default-dark-small .jstree-node {
+  min-height: 18px;
+  line-height: 18px;
+  margin-left: 18px;
+  min-width: 18px;
+}
+.jstree-default-dark-small .jstree-anchor {
+  line-height: 18px;
+  height: 18px;
+}
+.jstree-default-dark-small .jstree-icon {
+  width: 18px;
+  height: 18px;
+  line-height: 18px;
+}
+.jstree-default-dark-small .jstree-icon:empty {
+  width: 18px;
+  height: 18px;
+  line-height: 18px;
+}
+.jstree-default-dark-small.jstree-rtl .jstree-node {
+  margin-right: 18px;
+}
+.jstree-default-dark-small .jstree-wholerow {
+  height: 18px;
+}
+.jstree-default-dark-small .jstree-node,
+.jstree-default-dark-small .jstree-icon {
+  background-image: url("32px.png");
+}
+.jstree-default-dark-small .jstree-node {
+  background-position: -295px -7px;
+  background-repeat: repeat-y;
+}
+.jstree-default-dark-small .jstree-last {
+  background: transparent;
+}
+.jstree-default-dark-small .jstree-open > .jstree-ocl {
+  background-position: -135px -7px;
+}
+.jstree-default-dark-small .jstree-closed > .jstree-ocl {
+  background-position: -103px -7px;
+}
+.jstree-default-dark-small .jstree-leaf > .jstree-ocl {
+  background-position: -71px -7px;
+}
+.jstree-default-dark-small .jstree-themeicon {
+  background-position: -263px -7px;
+}
+.jstree-default-dark-small > .jstree-no-dots .jstree-node,
+.jstree-default-dark-small > .jstree-no-dots .jstree-leaf > .jstree-ocl {
+  background: transparent;
+}
+.jstree-default-dark-small > .jstree-no-dots .jstree-open > .jstree-ocl {
+  background-position: -39px -7px;
+}
+.jstree-default-dark-small > .jstree-no-dots .jstree-closed > .jstree-ocl {
+  background-position: -7px -7px;
+}
+.jstree-default-dark-small .jstree-disabled {
+  background: transparent;
+}
+.jstree-default-dark-small .jstree-disabled.jstree-hovered {
+  background: transparent;
+}
+.jstree-default-dark-small .jstree-disabled.jstree-clicked {
+  background: #efefef;
+}
+.jstree-default-dark-small .jstree-checkbox {
+  background-position: -167px -7px;
+}
+.jstree-default-dark-small .jstree-checkbox:hover {
+  background-position: -167px -39px;
+}
+.jstree-default-dark-small.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox,
+.jstree-default-dark-small .jstree-checked > .jstree-checkbox {
+  background-position: -231px -7px;
+}
+.jstree-default-dark-small.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover,
+.jstree-default-dark-small .jstree-checked > .jstree-checkbox:hover {
+  background-position: -231px -39px;
+}
+.jstree-default-dark-small .jstree-anchor > .jstree-undetermined {
+  background-position: -199px -7px;
+}
+.jstree-default-dark-small .jstree-anchor > .jstree-undetermined:hover {
+  background-position: -199px -39px;
+}
+.jstree-default-dark-small > .jstree-striped {
+  background-size: auto 36px;
+}
+.jstree-default-dark-small.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==");
+  background-position: 100% 1px;
+  background-repeat: repeat-y;
+}
+.jstree-default-dark-small.jstree-rtl .jstree-last {
+  background: transparent;
+}
+.jstree-default-dark-small.jstree-rtl .jstree-open > .jstree-ocl {
+  background-position: -135px -39px;
+}
+.jstree-default-dark-small.jstree-rtl .jstree-closed > .jstree-ocl {
+  background-position: -103px -39px;
+}
+.jstree-default-dark-small.jstree-rtl .jstree-leaf > .jstree-ocl {
+  background-position: -71px -39px;
+}
+.jstree-default-dark-small.jstree-rtl > .jstree-no-dots .jstree-node,
+.jstree-default-dark-small.jstree-rtl > .jstree-no-dots .jstree-leaf > .jstree-ocl {
+  background: transparent;
+}
+.jstree-default-dark-small.jstree-rtl > .jstree-no-dots .jstree-open > .jstree-ocl {
+  background-position: -39px -39px;
+}
+.jstree-default-dark-small.jstree-rtl > .jstree-no-dots .jstree-closed > .jstree-ocl {
+  background-position: -7px -39px;
+}
+.jstree-default-dark-small .jstree-themeicon-custom {
+  background-color: transparent;
+  background-image: none;
+  background-position: 0 0;
+}
+.jstree-default-dark-small > .jstree-container-ul .jstree-loading > .jstree-ocl {
+  background: url("throbber.gif") center center no-repeat;
+}
+.jstree-default-dark-small .jstree-file {
+  background: url("32px.png") -103px -71px no-repeat;
+}
+.jstree-default-dark-small .jstree-folder {
+  background: url("32px.png") -263px -7px no-repeat;
+}
+.jstree-default-dark-small > .jstree-container-ul > .jstree-node {
+  margin-left: 0;
+  margin-right: 0;
+}
+#jstree-dnd.jstree-default-dark-small {
+  line-height: 18px;
+  padding: 0 4px;
+}
+#jstree-dnd.jstree-default-dark-small .jstree-ok,
+#jstree-dnd.jstree-default-dark-small .jstree-er {
+  background-image: url("32px.png");
+  background-repeat: no-repeat;
+  background-color: transparent;
+}
+#jstree-dnd.jstree-default-dark-small i {
+  background: transparent;
+  width: 18px;
+  height: 18px;
+  line-height: 18px;
+}
+#jstree-dnd.jstree-default-dark-small .jstree-ok {
+  background-position: -7px -71px;
+}
+#jstree-dnd.jstree-default-dark-small .jstree-er {
+  background-position: -39px -71px;
+}
+.jstree-default-dark-small.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAACAQMAAABv1h6PAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMHBgAAiABBI4gz9AAAAABJRU5ErkJggg==");
+}
+.jstree-default-dark-small.jstree-rtl .jstree-last {
+  background: transparent;
+}
+.jstree-default-dark-large .jstree-node {
+  min-height: 32px;
+  line-height: 32px;
+  margin-left: 32px;
+  min-width: 32px;
+}
+.jstree-default-dark-large .jstree-anchor {
+  line-height: 32px;
+  height: 32px;
+}
+.jstree-default-dark-large .jstree-icon {
+  width: 32px;
+  height: 32px;
+  line-height: 32px;
+}
+.jstree-default-dark-large .jstree-icon:empty {
+  width: 32px;
+  height: 32px;
+  line-height: 32px;
+}
+.jstree-default-dark-large.jstree-rtl .jstree-node {
+  margin-right: 32px;
+}
+.jstree-default-dark-large .jstree-wholerow {
+  height: 32px;
+}
+.jstree-default-dark-large .jstree-node,
+.jstree-default-dark-large .jstree-icon {
+  background-image: url("32px.png");
+}
+.jstree-default-dark-large .jstree-node {
+  background-position: -288px 0px;
+  background-repeat: repeat-y;
+}
+.jstree-default-dark-large .jstree-last {
+  background: transparent;
+}
+.jstree-default-dark-large .jstree-open > .jstree-ocl {
+  background-position: -128px 0px;
+}
+.jstree-default-dark-large .jstree-closed > .jstree-ocl {
+  background-position: -96px 0px;
+}
+.jstree-default-dark-large .jstree-leaf > .jstree-ocl {
+  background-position: -64px 0px;
+}
+.jstree-default-dark-large .jstree-themeicon {
+  background-position: -256px 0px;
+}
+.jstree-default-dark-large > .jstree-no-dots .jstree-node,
+.jstree-default-dark-large > .jstree-no-dots .jstree-leaf > .jstree-ocl {
+  background: transparent;
+}
+.jstree-default-dark-large > .jstree-no-dots .jstree-open > .jstree-ocl {
+  background-position: -32px 0px;
+}
+.jstree-default-dark-large > .jstree-no-dots .jstree-closed > .jstree-ocl {
+  background-position: 0px 0px;
+}
+.jstree-default-dark-large .jstree-disabled {
+  background: transparent;
+}
+.jstree-default-dark-large .jstree-disabled.jstree-hovered {
+  background: transparent;
+}
+.jstree-default-dark-large .jstree-disabled.jstree-clicked {
+  background: #efefef;
+}
+.jstree-default-dark-large .jstree-checkbox {
+  background-position: -160px 0px;
+}
+.jstree-default-dark-large .jstree-checkbox:hover {
+  background-position: -160px -32px;
+}
+.jstree-default-dark-large.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox,
+.jstree-default-dark-large .jstree-checked > .jstree-checkbox {
+  background-position: -224px 0px;
+}
+.jstree-default-dark-large.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover,
+.jstree-default-dark-large .jstree-checked > .jstree-checkbox:hover {
+  background-position: -224px -32px;
+}
+.jstree-default-dark-large .jstree-anchor > .jstree-undetermined {
+  background-position: -192px 0px;
+}
+.jstree-default-dark-large .jstree-anchor > .jstree-undetermined:hover {
+  background-position: -192px -32px;
+}
+.jstree-default-dark-large > .jstree-striped {
+  background-size: auto 64px;
+}
+.jstree-default-dark-large.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==");
+  background-position: 100% 1px;
+  background-repeat: repeat-y;
+}
+.jstree-default-dark-large.jstree-rtl .jstree-last {
+  background: transparent;
+}
+.jstree-default-dark-large.jstree-rtl .jstree-open > .jstree-ocl {
+  background-position: -128px -32px;
+}
+.jstree-default-dark-large.jstree-rtl .jstree-closed > .jstree-ocl {
+  background-position: -96px -32px;
+}
+.jstree-default-dark-large.jstree-rtl .jstree-leaf > .jstree-ocl {
+  background-position: -64px -32px;
+}
+.jstree-default-dark-large.jstree-rtl > .jstree-no-dots .jstree-node,
+.jstree-default-dark-large.jstree-rtl > .jstree-no-dots .jstree-leaf > .jstree-ocl {
+  background: transparent;
+}
+.jstree-default-dark-large.jstree-rtl > .jstree-no-dots .jstree-open > .jstree-ocl {
+  background-position: -32px -32px;
+}
+.jstree-default-dark-large.jstree-rtl > .jstree-no-dots .jstree-closed > .jstree-ocl {
+  background-position: 0px -32px;
+}
+.jstree-default-dark-large .jstree-themeicon-custom {
+  background-color: transparent;
+  background-image: none;
+  background-position: 0 0;
+}
+.jstree-default-dark-large > .jstree-container-ul .jstree-loading > .jstree-ocl {
+  background: url("throbber.gif") center center no-repeat;
+}
+.jstree-default-dark-large .jstree-file {
+  background: url("32px.png") -96px -64px no-repeat;
+}
+.jstree-default-dark-large .jstree-folder {
+  background: url("32px.png") -256px 0px no-repeat;
+}
+.jstree-default-dark-large > .jstree-container-ul > .jstree-node {
+  margin-left: 0;
+  margin-right: 0;
+}
+#jstree-dnd.jstree-default-dark-large {
+  line-height: 32px;
+  padding: 0 4px;
+}
+#jstree-dnd.jstree-default-dark-large .jstree-ok,
+#jstree-dnd.jstree-default-dark-large .jstree-er {
+  background-image: url("32px.png");
+  background-repeat: no-repeat;
+  background-color: transparent;
+}
+#jstree-dnd.jstree-default-dark-large i {
+  background: transparent;
+  width: 32px;
+  height: 32px;
+  line-height: 32px;
+}
+#jstree-dnd.jstree-default-dark-large .jstree-ok {
+  background-position: 0px -64px;
+}
+#jstree-dnd.jstree-default-dark-large .jstree-er {
+  background-position: -32px -64px;
+}
+.jstree-default-dark-large.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAACAQMAAAAD0EyKAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjgIIGBgABCgCBvVLXcAAAAABJRU5ErkJggg==");
+}
+.jstree-default-dark-large.jstree-rtl .jstree-last {
+  background: transparent;
+}
+@media (max-width: 768px) {
+  #jstree-dnd.jstree-dnd-responsive {
+    line-height: 40px;
+    font-weight: bold;
+    font-size: 1.1em;
+    text-shadow: 1px 1px white;
+  }
+  #jstree-dnd.jstree-dnd-responsive > i {
+    background: transparent;
+    width: 40px;
+    height: 40px;
+  }
+  #jstree-dnd.jstree-dnd-responsive > .jstree-ok {
+    background-image: url("40px.png");
+    background-position: 0 -200px;
+    background-size: 120px 240px;
+  }
+  #jstree-dnd.jstree-dnd-responsive > .jstree-er {
+    background-image: url("40px.png");
+    background-position: -40px -200px;
+    background-size: 120px 240px;
+  }
+  #jstree-marker.jstree-dnd-responsive {
+    border-left-width: 10px;
+    border-top-width: 10px;
+    border-bottom-width: 10px;
+    margin-top: -10px;
+  }
+}
+@media (max-width: 768px) {
+  .jstree-default-dark-responsive {
+    /*
+	.jstree-open > .jstree-ocl,
+	.jstree-closed > .jstree-ocl { border-radius:20px; background-color:white; }
+	*/
+  }
+  .jstree-default-dark-responsive .jstree-icon {
+    background-image: url("40px.png");
+  }
+  .jstree-default-dark-responsive .jstree-node,
+  .jstree-default-dark-responsive .jstree-leaf > .jstree-ocl {
+    background: transparent;
+  }
+  .jstree-default-dark-responsive .jstree-node {
+    min-height: 40px;
+    line-height: 40px;
+    margin-left: 40px;
+    min-width: 40px;
+    white-space: nowrap;
+  }
+  .jstree-default-dark-responsive .jstree-anchor {
+    line-height: 40px;
+    height: 40px;
+  }
+  .jstree-default-dark-responsive .jstree-icon,
+  .jstree-default-dark-responsive .jstree-icon:empty {
+    width: 40px;
+    height: 40px;
+    line-height: 40px;
+  }
+  .jstree-default-dark-responsive > .jstree-container-ul > .jstree-node {
+    margin-left: 0;
+  }
+  .jstree-default-dark-responsive.jstree-rtl .jstree-node {
+    margin-left: 0;
+    margin-right: 40px;
+  }
+  .jstree-default-dark-responsive.jstree-rtl .jstree-container-ul > .jstree-node {
+    margin-right: 0;
+  }
+  .jstree-default-dark-responsive .jstree-ocl,
+  .jstree-default-dark-responsive .jstree-themeicon,
+  .jstree-default-dark-responsive .jstree-checkbox {
+    background-size: 120px 240px;
+  }
+  .jstree-default-dark-responsive .jstree-leaf > .jstree-ocl {
+    background: transparent;
+  }
+  .jstree-default-dark-responsive .jstree-open > .jstree-ocl {
+    background-position: 0 0px !important;
+  }
+  .jstree-default-dark-responsive .jstree-closed > .jstree-ocl {
+    background-position: 0 -40px !important;
+  }
+  .jstree-default-dark-responsive.jstree-rtl .jstree-closed > .jstree-ocl {
+    background-position: -40px 0px !important;
+  }
+  .jstree-default-dark-responsive .jstree-themeicon {
+    background-position: -40px -40px;
+  }
+  .jstree-default-dark-responsive .jstree-checkbox,
+  .jstree-default-dark-responsive .jstree-checkbox:hover {
+    background-position: -40px -80px;
+  }
+  .jstree-default-dark-responsive.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox,
+  .jstree-default-dark-responsive.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover,
+  .jstree-default-dark-responsive .jstree-checked > .jstree-checkbox,
+  .jstree-default-dark-responsive .jstree-checked > .jstree-checkbox:hover {
+    background-position: 0 -80px;
+  }
+  .jstree-default-dark-responsive .jstree-anchor > .jstree-undetermined,
+  .jstree-default-dark-responsive .jstree-anchor > .jstree-undetermined:hover {
+    background-position: 0 -120px;
+  }
+  .jstree-default-dark-responsive .jstree-anchor {
+    font-weight: bold;
+    font-size: 1.1em;
+    text-shadow: 1px 1px white;
+  }
+  .jstree-default-dark-responsive > .jstree-striped {
+    background: transparent;
+  }
+  .jstree-default-dark-responsive .jstree-wholerow {
+    border-top: 1px solid #666666;
+    border-bottom: 1px solid #000000;
+    background: #333333;
+    height: 40px;
+  }
+  .jstree-default-dark-responsive .jstree-wholerow-hovered {
+    background: #555555;
+  }
+  .jstree-default-dark-responsive .jstree-wholerow-clicked {
+    background: #5fa2db;
+  }
+  .jstree-default-dark-responsive .jstree-children .jstree-last > .jstree-wholerow {
+    box-shadow: inset 0 -6px 3px -5px #111111;
+  }
+  .jstree-default-dark-responsive .jstree-children .jstree-open > .jstree-wholerow {
+    box-shadow: inset 0 6px 3px -5px #111111;
+    border-top: 0;
+  }
+  .jstree-default-dark-responsive .jstree-children .jstree-open + .jstree-open {
+    box-shadow: none;
+  }
+  .jstree-default-dark-responsive .jstree-node,
+  .jstree-default-dark-responsive .jstree-icon,
+  .jstree-default-dark-responsive .jstree-node > .jstree-ocl,
+  .jstree-default-dark-responsive .jstree-themeicon,
+  .jstree-default-dark-responsive .jstree-checkbox {
+    background-image: url("40px.png");
+    background-size: 120px 240px;
+  }
+  .jstree-default-dark-responsive .jstree-node {
+    background-position: -80px 0;
+    background-repeat: repeat-y;
+  }
+  .jstree-default-dark-responsive .jstree-last {
+    background: transparent;
+  }
+  .jstree-default-dark-responsive .jstree-leaf > .jstree-ocl {
+    background-position: -40px -120px;
+  }
+  .jstree-default-dark-responsive .jstree-last > .jstree-ocl {
+    background-position: -40px -160px;
+  }
+  .jstree-default-dark-responsive .jstree-themeicon-custom {
+    background-color: transparent;
+    background-image: none;
+    background-position: 0 0;
+  }
+  .jstree-default-dark-responsive .jstree-file {
+    background: url("40px.png") 0 -160px no-repeat;
+    background-size: 120px 240px;
+  }
+  .jstree-default-dark-responsive .jstree-folder {
+    background: url("40px.png") -40px -40px no-repeat;
+    background-size: 120px 240px;
+  }
+  .jstree-default-dark-responsive > .jstree-container-ul > .jstree-node {
+    margin-left: 0;
+    margin-right: 0;
+  }
+}
+.jstree-default-dark {
+  background: #333;
+}
+.jstree-default-dark .jstree-anchor {
+  color: #999;
+  text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.5);
+}
+.jstree-default-dark .jstree-clicked,
+.jstree-default-dark .jstree-checked {
+  color: white;
+}
+.jstree-default-dark .jstree-hovered {
+  color: white;
+}
+#jstree-marker.jstree-default-dark {
+  border-left-color: #999;
+  background: transparent;
+}
+.jstree-default-dark .jstree-anchor > .jstree-icon {
+  opacity: 0.75;
+}
+.jstree-default-dark .jstree-clicked > .jstree-icon,
+.jstree-default-dark .jstree-hovered > .jstree-icon,
+.jstree-default-dark .jstree-checked > .jstree-icon {
+  opacity: 1;
+}
+.jstree-default-dark.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAACZmZl+9SADAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==");
+}
+.jstree-default-dark.jstree-rtl .jstree-last {
+  background: transparent;
+}
+.jstree-default-dark-small.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAACAQMAAABv1h6PAAAABlBMVEUAAACZmZl+9SADAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMHBgAAiABBI4gz9AAAAABJRU5ErkJggg==");
+}
+.jstree-default-dark-small.jstree-rtl .jstree-last {
+  background: transparent;
+}
+.jstree-default-dark-large.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAACAQMAAAAD0EyKAAAABlBMVEUAAACZmZl+9SADAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjgIIGBgABCgCBvVLXcAAAAABJRU5ErkJggg==");
+}
+.jstree-default-dark-large.jstree-rtl .jstree-last {
+  background: transparent;
+}
diff --git a/htdocs/Libs/jsTree/themes/default-dark/style.min.css b/htdocs/Libs/jsTree/themes/default-dark/style.min.css
new file mode 100644
index 0000000..6403484
--- /dev/null
+++ b/htdocs/Libs/jsTree/themes/default-dark/style.min.css
@@ -0,0 +1 @@
+.jstree-node,.jstree-children,.jstree-container-ul{display:block;margin:0;padding:0;list-style-type:none;list-style-image:none}.jstree-node{white-space:nowrap}.jstree-anchor{display:inline-block;color:#000;white-space:nowrap;padding:0 4px 0 1px;margin:0;vertical-align:top}.jstree-anchor:focus{outline:0}.jstree-anchor,.jstree-anchor:link,.jstree-anchor:visited,.jstree-anchor:hover,.jstree-anchor:active{text-decoration:none;color:inherit}.jstree-icon{display:inline-block;text-decoration:none;margin:0;padding:0;vertical-align:top;text-align:center}.jstree-icon:empty{display:inline-block;text-decoration:none;margin:0;padding:0;vertical-align:top;text-align:center}.jstree-ocl{cursor:pointer}.jstree-leaf>.jstree-ocl{cursor:default}.jstree .jstree-open>.jstree-children{display:block}.jstree .jstree-closed>.jstree-children,.jstree .jstree-leaf>.jstree-children{display:none}.jstree-anchor>.jstree-themeicon{margin-right:2px}.jstree-no-icons .jstree-themeicon,.jstree-anchor>.jstree-themeicon-hidden{display:none}.jstree-rtl .jstree-anchor{padding:0 1px 0 4px}.jstree-rtl .jstree-anchor>.jstree-themeicon{margin-left:2px;margin-right:0}.jstree-rtl .jstree-node{margin-left:0}.jstree-rtl .jstree-container-ul>.jstree-node{margin-right:0}.jstree-wholerow-ul{position:relative;display:inline-block;min-width:100%}.jstree-wholerow-ul .jstree-leaf>.jstree-ocl{cursor:pointer}.jstree-wholerow-ul .jstree-anchor,.jstree-wholerow-ul .jstree-icon{position:relative}.jstree-wholerow-ul .jstree-wholerow{width:100%;cursor:pointer;position:absolute;left:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.vakata-context{display:none}.vakata-context,.vakata-context ul{margin:0;padding:2px;position:absolute;background:#f5f5f5;border:1px solid #979797;-moz-box-shadow:5px 5px 4px -4px #666;-webkit-box-shadow:2px 2px 2px #999;box-shadow:2px 2px 2px #999}.vakata-context ul{list-style:none;left:100%;margin-top:-2.7em;margin-left:-4px}.vakata-context .vakata-context-right ul{left:auto;right:100%;margin-left:auto;margin-right:-4px}.vakata-context li{list-style:none;display:inline}.vakata-context li>a{display:block;padding:0 2em;text-decoration:none;width:auto;color:#000;white-space:nowrap;line-height:2.4em;-moz-text-shadow:1px 1px 0 #fff;-webkit-text-shadow:1px 1px 0 #fff;text-shadow:1px 1px 0 #fff;-moz-border-radius:1px;-webkit-border-radius:1px;border-radius:1px}.vakata-context li>a:hover{position:relative;background-color:#e8eff7;-moz-box-shadow:0 0 2px #0a6aa1;-webkit-box-shadow:0 0 2px #0a6aa1;box-shadow:0 0 2px #0a6aa1}.vakata-context li>a.vakata-context-parent{background-image:url(data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAIORI4JlrqN1oMSnmmZDQUAOw==);background-position:right center;background-repeat:no-repeat}.vakata-context li>a:focus{outline:0}.vakata-context .vakata-context-hover>a{position:relative;background-color:#e8eff7;-moz-box-shadow:0 0 2px #0a6aa1;-webkit-box-shadow:0 0 2px #0a6aa1;box-shadow:0 0 2px #0a6aa1}.vakata-context .vakata-context-separator>a,.vakata-context .vakata-context-separator>a:hover{background:#fff;border:0;border-top:1px solid #e2e3e3;height:1px;min-height:1px;max-height:1px;padding:0;margin:0 0 0 2.4em;border-left:1px solid #e0e0e0;-moz-text-shadow:0 0 0 transparent;-webkit-text-shadow:0 0 0 transparent;text-shadow:0 0 0 transparent;-moz-box-shadow:0 0 0 transparent;-webkit-box-shadow:0 0 0 transparent;box-shadow:0 0 0 transparent;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.vakata-context .vakata-contextmenu-disabled a,.vakata-context .vakata-contextmenu-disabled a:hover{color:silver;background-color:transparent;border:0;box-shadow:0 0 0}.vakata-context li>a>i{text-decoration:none;display:inline-block;width:2.4em;height:2.4em;background:0 0;margin:0 0 0 -2em;vertical-align:top;text-align:center;line-height:2.4em}.vakata-context li>a>i:empty{width:2.4em;line-height:2.4em}.vakata-context li>a .vakata-contextmenu-sep{display:inline-block;width:1px;height:2.4em;background:#fff;margin:0 .5em 0 0;border-left:1px solid #e2e3e3}.vakata-context .vakata-contextmenu-shortcut{font-size:.8em;color:silver;opacity:.5;display:none}.vakata-context-rtl ul{left:auto;right:100%;margin-left:auto;margin-right:-4px}.vakata-context-rtl li>a.vakata-context-parent{background-image:url(data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAINjI+AC7rWHIsPtmoxLAA7);background-position:left center;background-repeat:no-repeat}.vakata-context-rtl .vakata-context-separator>a{margin:0 2.4em 0 0;border-left:0;border-right:1px solid #e2e3e3}.vakata-context-rtl .vakata-context-left ul{right:auto;left:100%;margin-left:-4px;margin-right:auto}.vakata-context-rtl li>a>i{margin:0 -2em 0 0}.vakata-context-rtl li>a .vakata-contextmenu-sep{margin:0 0 0 .5em;border-left-color:#fff;background:#e2e3e3}#jstree-marker{position:absolute;top:0;left:0;margin:-5px 0 0 0;padding:0;border-right:0;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid;width:0;height:0;font-size:0;line-height:0}#jstree-dnd{line-height:16px;margin:0;padding:4px}#jstree-dnd .jstree-icon,#jstree-dnd .jstree-copy{display:inline-block;text-decoration:none;margin:0 2px 0 0;padding:0;width:16px;height:16px}#jstree-dnd .jstree-ok{background:green}#jstree-dnd .jstree-er{background:red}#jstree-dnd .jstree-copy{margin:0 2px}.jstree-default-dark .jstree-node,.jstree-default-dark .jstree-icon{background-repeat:no-repeat;background-color:transparent}.jstree-default-dark .jstree-anchor,.jstree-default-dark .jstree-wholerow{transition:background-color .15s,box-shadow .15s}.jstree-default-dark .jstree-hovered{background:#555;border-radius:2px;box-shadow:inset 0 0 1px #555}.jstree-default-dark .jstree-clicked{background:#5fa2db;border-radius:2px;box-shadow:inset 0 0 1px #666}.jstree-default-dark .jstree-no-icons .jstree-anchor>.jstree-themeicon{display:none}.jstree-default-dark .jstree-disabled{background:0 0;color:#666}.jstree-default-dark .jstree-disabled.jstree-hovered{background:0 0;box-shadow:none}.jstree-default-dark .jstree-disabled.jstree-clicked{background:#333}.jstree-default-dark .jstree-disabled>.jstree-icon{opacity:.8;filter:url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'jstree-grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#jstree-grayscale");filter:gray;-webkit-filter:grayscale(100%)}.jstree-default-dark .jstree-search{font-style:italic;color:#fff;font-weight:700}.jstree-default-dark .jstree-no-checkboxes .jstree-checkbox{display:none!important}.jstree-default-dark.jstree-checkbox-no-clicked .jstree-clicked{background:0 0;box-shadow:none}.jstree-default-dark.jstree-checkbox-no-clicked .jstree-clicked.jstree-hovered{background:#555}.jstree-default-dark.jstree-checkbox-no-clicked>.jstree-wholerow-ul .jstree-wholerow-clicked{background:0 0}.jstree-default-dark.jstree-checkbox-no-clicked>.jstree-wholerow-ul .jstree-wholerow-clicked.jstree-wholerow-hovered{background:#555}.jstree-default-dark>.jstree-striped{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAMAAAB/qqA+AAAABlBMVEUAAAAAAAClZ7nPAAAAAnRSTlMNAMM9s3UAAAAXSURBVHjajcEBAQAAAIKg/H/aCQZ70AUBjAATb6YPDgAAAABJRU5ErkJggg==) left top repeat}.jstree-default-dark>.jstree-wholerow-ul .jstree-hovered,.jstree-default-dark>.jstree-wholerow-ul .jstree-clicked{background:0 0;box-shadow:none;border-radius:0}.jstree-default-dark .jstree-wholerow{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.jstree-default-dark .jstree-wholerow-hovered{background:#555}.jstree-default-dark .jstree-wholerow-clicked{background:#5fa2db;background:-moz-linear-gradient(top,#5fa2db 0,#5fa2db 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#5fa2db),color-stop(100%,#5fa2db));background:-webkit-linear-gradient(top,#5fa2db 0,#5fa2db 100%);background:-o-linear-gradient(top,#5fa2db 0,#5fa2db 100%);background:-ms-linear-gradient(top,#5fa2db 0,#5fa2db 100%);background:linear-gradient(to bottom,#5fa2db 0,#5fa2db 100%)}.jstree-default-dark .jstree-node{min-height:24px;line-height:24px;margin-left:24px;min-width:24px}.jstree-default-dark .jstree-anchor{line-height:24px;height:24px}.jstree-default-dark .jstree-icon{width:24px;height:24px;line-height:24px}.jstree-default-dark .jstree-icon:empty{width:24px;height:24px;line-height:24px}.jstree-default-dark.jstree-rtl .jstree-node{margin-right:24px}.jstree-default-dark .jstree-wholerow{height:24px}.jstree-default-dark .jstree-node,.jstree-default-dark .jstree-icon{background-image:url(32px.png)}.jstree-default-dark .jstree-node{background-position:-292px -4px;background-repeat:repeat-y}.jstree-default-dark .jstree-last{background:0 0}.jstree-default-dark .jstree-open>.jstree-ocl{background-position:-132px -4px}.jstree-default-dark .jstree-closed>.jstree-ocl{background-position:-100px -4px}.jstree-default-dark .jstree-leaf>.jstree-ocl{background-position:-68px -4px}.jstree-default-dark .jstree-themeicon{background-position:-260px -4px}.jstree-default-dark>.jstree-no-dots .jstree-node,.jstree-default-dark>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-dark>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-36px -4px}.jstree-default-dark>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-4px -4px}.jstree-default-dark .jstree-disabled{background:0 0}.jstree-default-dark .jstree-disabled.jstree-hovered{background:0 0}.jstree-default-dark .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default-dark .jstree-checkbox{background-position:-164px -4px}.jstree-default-dark .jstree-checkbox:hover{background-position:-164px -36px}.jstree-default-dark.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox,.jstree-default-dark .jstree-checked>.jstree-checkbox{background-position:-228px -4px}.jstree-default-dark.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox:hover,.jstree-default-dark .jstree-checked>.jstree-checkbox:hover{background-position:-228px -36px}.jstree-default-dark .jstree-anchor>.jstree-undetermined{background-position:-196px -4px}.jstree-default-dark .jstree-anchor>.jstree-undetermined:hover{background-position:-196px -36px}.jstree-default-dark>.jstree-striped{background-size:auto 48px}.jstree-default-dark.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==);background-position:100% 1px;background-repeat:repeat-y}.jstree-default-dark.jstree-rtl .jstree-last{background:0 0}.jstree-default-dark.jstree-rtl .jstree-open>.jstree-ocl{background-position:-132px -36px}.jstree-default-dark.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-100px -36px}.jstree-default-dark.jstree-rtl .jstree-leaf>.jstree-ocl{background-position:-68px -36px}.jstree-default-dark.jstree-rtl>.jstree-no-dots .jstree-node,.jstree-default-dark.jstree-rtl>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-dark.jstree-rtl>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-36px -36px}.jstree-default-dark.jstree-rtl>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-4px -36px}.jstree-default-dark .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default-dark>.jstree-container-ul .jstree-loading>.jstree-ocl{background:url(throbber.gif) center center no-repeat}.jstree-default-dark .jstree-file{background:url(32px.png) -100px -68px no-repeat}.jstree-default-dark .jstree-folder{background:url(32px.png) -260px -4px no-repeat}.jstree-default-dark>.jstree-container-ul>.jstree-node{margin-left:0;margin-right:0}#jstree-dnd.jstree-default-dark{line-height:24px;padding:0 4px}#jstree-dnd.jstree-default-dark .jstree-ok,#jstree-dnd.jstree-default-dark .jstree-er{background-image:url(32px.png);background-repeat:no-repeat;background-color:transparent}#jstree-dnd.jstree-default-dark i{background:0 0;width:24px;height:24px;line-height:24px}#jstree-dnd.jstree-default-dark .jstree-ok{background-position:-4px -68px}#jstree-dnd.jstree-default-dark .jstree-er{background-position:-36px -68px}.jstree-default-dark.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==)}.jstree-default-dark.jstree-rtl .jstree-last{background:0 0}.jstree-default-dark-small .jstree-node{min-height:18px;line-height:18px;margin-left:18px;min-width:18px}.jstree-default-dark-small .jstree-anchor{line-height:18px;height:18px}.jstree-default-dark-small .jstree-icon{width:18px;height:18px;line-height:18px}.jstree-default-dark-small .jstree-icon:empty{width:18px;height:18px;line-height:18px}.jstree-default-dark-small.jstree-rtl .jstree-node{margin-right:18px}.jstree-default-dark-small .jstree-wholerow{height:18px}.jstree-default-dark-small .jstree-node,.jstree-default-dark-small .jstree-icon{background-image:url(32px.png)}.jstree-default-dark-small .jstree-node{background-position:-295px -7px;background-repeat:repeat-y}.jstree-default-dark-small .jstree-last{background:0 0}.jstree-default-dark-small .jstree-open>.jstree-ocl{background-position:-135px -7px}.jstree-default-dark-small .jstree-closed>.jstree-ocl{background-position:-103px -7px}.jstree-default-dark-small .jstree-leaf>.jstree-ocl{background-position:-71px -7px}.jstree-default-dark-small .jstree-themeicon{background-position:-263px -7px}.jstree-default-dark-small>.jstree-no-dots .jstree-node,.jstree-default-dark-small>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-dark-small>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-39px -7px}.jstree-default-dark-small>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-7px -7px}.jstree-default-dark-small .jstree-disabled{background:0 0}.jstree-default-dark-small .jstree-disabled.jstree-hovered{background:0 0}.jstree-default-dark-small .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default-dark-small .jstree-checkbox{background-position:-167px -7px}.jstree-default-dark-small .jstree-checkbox:hover{background-position:-167px -39px}.jstree-default-dark-small.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox,.jstree-default-dark-small .jstree-checked>.jstree-checkbox{background-position:-231px -7px}.jstree-default-dark-small.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox:hover,.jstree-default-dark-small .jstree-checked>.jstree-checkbox:hover{background-position:-231px -39px}.jstree-default-dark-small .jstree-anchor>.jstree-undetermined{background-position:-199px -7px}.jstree-default-dark-small .jstree-anchor>.jstree-undetermined:hover{background-position:-199px -39px}.jstree-default-dark-small>.jstree-striped{background-size:auto 36px}.jstree-default-dark-small.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==);background-position:100% 1px;background-repeat:repeat-y}.jstree-default-dark-small.jstree-rtl .jstree-last{background:0 0}.jstree-default-dark-small.jstree-rtl .jstree-open>.jstree-ocl{background-position:-135px -39px}.jstree-default-dark-small.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-103px -39px}.jstree-default-dark-small.jstree-rtl .jstree-leaf>.jstree-ocl{background-position:-71px -39px}.jstree-default-dark-small.jstree-rtl>.jstree-no-dots .jstree-node,.jstree-default-dark-small.jstree-rtl>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-dark-small.jstree-rtl>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-39px -39px}.jstree-default-dark-small.jstree-rtl>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-7px -39px}.jstree-default-dark-small .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default-dark-small>.jstree-container-ul .jstree-loading>.jstree-ocl{background:url(throbber.gif) center center no-repeat}.jstree-default-dark-small .jstree-file{background:url(32px.png) -103px -71px no-repeat}.jstree-default-dark-small .jstree-folder{background:url(32px.png) -263px -7px no-repeat}.jstree-default-dark-small>.jstree-container-ul>.jstree-node{margin-left:0;margin-right:0}#jstree-dnd.jstree-default-dark-small{line-height:18px;padding:0 4px}#jstree-dnd.jstree-default-dark-small .jstree-ok,#jstree-dnd.jstree-default-dark-small .jstree-er{background-image:url(32px.png);background-repeat:no-repeat;background-color:transparent}#jstree-dnd.jstree-default-dark-small i{background:0 0;width:18px;height:18px;line-height:18px}#jstree-dnd.jstree-default-dark-small .jstree-ok{background-position:-7px -71px}#jstree-dnd.jstree-default-dark-small .jstree-er{background-position:-39px -71px}.jstree-default-dark-small.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAACAQMAAABv1h6PAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMHBgAAiABBI4gz9AAAAABJRU5ErkJggg==)}.jstree-default-dark-small.jstree-rtl .jstree-last{background:0 0}.jstree-default-dark-large .jstree-node{min-height:32px;line-height:32px;margin-left:32px;min-width:32px}.jstree-default-dark-large .jstree-anchor{line-height:32px;height:32px}.jstree-default-dark-large .jstree-icon{width:32px;height:32px;line-height:32px}.jstree-default-dark-large .jstree-icon:empty{width:32px;height:32px;line-height:32px}.jstree-default-dark-large.jstree-rtl .jstree-node{margin-right:32px}.jstree-default-dark-large .jstree-wholerow{height:32px}.jstree-default-dark-large .jstree-node,.jstree-default-dark-large .jstree-icon{background-image:url(32px.png)}.jstree-default-dark-large .jstree-node{background-position:-288px 0;background-repeat:repeat-y}.jstree-default-dark-large .jstree-last{background:0 0}.jstree-default-dark-large .jstree-open>.jstree-ocl{background-position:-128px 0}.jstree-default-dark-large .jstree-closed>.jstree-ocl{background-position:-96px 0}.jstree-default-dark-large .jstree-leaf>.jstree-ocl{background-position:-64px 0}.jstree-default-dark-large .jstree-themeicon{background-position:-256px 0}.jstree-default-dark-large>.jstree-no-dots .jstree-node,.jstree-default-dark-large>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-dark-large>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-32px 0}.jstree-default-dark-large>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:0 0}.jstree-default-dark-large .jstree-disabled{background:0 0}.jstree-default-dark-large .jstree-disabled.jstree-hovered{background:0 0}.jstree-default-dark-large .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default-dark-large .jstree-checkbox{background-position:-160px 0}.jstree-default-dark-large .jstree-checkbox:hover{background-position:-160px -32px}.jstree-default-dark-large.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox,.jstree-default-dark-large .jstree-checked>.jstree-checkbox{background-position:-224px 0}.jstree-default-dark-large.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox:hover,.jstree-default-dark-large .jstree-checked>.jstree-checkbox:hover{background-position:-224px -32px}.jstree-default-dark-large .jstree-anchor>.jstree-undetermined{background-position:-192px 0}.jstree-default-dark-large .jstree-anchor>.jstree-undetermined:hover{background-position:-192px -32px}.jstree-default-dark-large>.jstree-striped{background-size:auto 64px}.jstree-default-dark-large.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==);background-position:100% 1px;background-repeat:repeat-y}.jstree-default-dark-large.jstree-rtl .jstree-last{background:0 0}.jstree-default-dark-large.jstree-rtl .jstree-open>.jstree-ocl{background-position:-128px -32px}.jstree-default-dark-large.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-96px -32px}.jstree-default-dark-large.jstree-rtl .jstree-leaf>.jstree-ocl{background-position:-64px -32px}.jstree-default-dark-large.jstree-rtl>.jstree-no-dots .jstree-node,.jstree-default-dark-large.jstree-rtl>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-dark-large.jstree-rtl>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-32px -32px}.jstree-default-dark-large.jstree-rtl>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:0 -32px}.jstree-default-dark-large .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default-dark-large>.jstree-container-ul .jstree-loading>.jstree-ocl{background:url(throbber.gif) center center no-repeat}.jstree-default-dark-large .jstree-file{background:url(32px.png) -96px -64px no-repeat}.jstree-default-dark-large .jstree-folder{background:url(32px.png) -256px 0 no-repeat}.jstree-default-dark-large>.jstree-container-ul>.jstree-node{margin-left:0;margin-right:0}#jstree-dnd.jstree-default-dark-large{line-height:32px;padding:0 4px}#jstree-dnd.jstree-default-dark-large .jstree-ok,#jstree-dnd.jstree-default-dark-large .jstree-er{background-image:url(32px.png);background-repeat:no-repeat;background-color:transparent}#jstree-dnd.jstree-default-dark-large i{background:0 0;width:32px;height:32px;line-height:32px}#jstree-dnd.jstree-default-dark-large .jstree-ok{background-position:0 -64px}#jstree-dnd.jstree-default-dark-large .jstree-er{background-position:-32px -64px}.jstree-default-dark-large.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAACAQMAAAAD0EyKAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjgIIGBgABCgCBvVLXcAAAAABJRU5ErkJggg==)}.jstree-default-dark-large.jstree-rtl .jstree-last{background:0 0}@media (max-width:768px){#jstree-dnd.jstree-dnd-responsive{line-height:40px;font-weight:700;font-size:1.1em;text-shadow:1px 1px #fff}#jstree-dnd.jstree-dnd-responsive>i{background:0 0;width:40px;height:40px}#jstree-dnd.jstree-dnd-responsive>.jstree-ok{background-image:url(40px.png);background-position:0 -200px;background-size:120px 240px}#jstree-dnd.jstree-dnd-responsive>.jstree-er{background-image:url(40px.png);background-position:-40px -200px;background-size:120px 240px}#jstree-marker.jstree-dnd-responsive{border-left-width:10px;border-top-width:10px;border-bottom-width:10px;margin-top:-10px}}@media (max-width:768px){.jstree-default-dark-responsive .jstree-icon{background-image:url(40px.png)}.jstree-default-dark-responsive .jstree-node,.jstree-default-dark-responsive .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-dark-responsive .jstree-node{min-height:40px;line-height:40px;margin-left:40px;min-width:40px;white-space:nowrap}.jstree-default-dark-responsive .jstree-anchor{line-height:40px;height:40px}.jstree-default-dark-responsive .jstree-icon,.jstree-default-dark-responsive .jstree-icon:empty{width:40px;height:40px;line-height:40px}.jstree-default-dark-responsive>.jstree-container-ul>.jstree-node{margin-left:0}.jstree-default-dark-responsive.jstree-rtl .jstree-node{margin-left:0;margin-right:40px}.jstree-default-dark-responsive.jstree-rtl .jstree-container-ul>.jstree-node{margin-right:0}.jstree-default-dark-responsive .jstree-ocl,.jstree-default-dark-responsive .jstree-themeicon,.jstree-default-dark-responsive .jstree-checkbox{background-size:120px 240px}.jstree-default-dark-responsive .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-dark-responsive .jstree-open>.jstree-ocl{background-position:0 0!important}.jstree-default-dark-responsive .jstree-closed>.jstree-ocl{background-position:0 -40px!important}.jstree-default-dark-responsive.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-40px 0!important}.jstree-default-dark-responsive .jstree-themeicon{background-position:-40px -40px}.jstree-default-dark-responsive .jstree-checkbox,.jstree-default-dark-responsive .jstree-checkbox:hover{background-position:-40px -80px}.jstree-default-dark-responsive.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox,.jstree-default-dark-responsive.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox:hover,.jstree-default-dark-responsive .jstree-checked>.jstree-checkbox,.jstree-default-dark-responsive .jstree-checked>.jstree-checkbox:hover{background-position:0 -80px}.jstree-default-dark-responsive .jstree-anchor>.jstree-undetermined,.jstree-default-dark-responsive .jstree-anchor>.jstree-undetermined:hover{background-position:0 -120px}.jstree-default-dark-responsive .jstree-anchor{font-weight:700;font-size:1.1em;text-shadow:1px 1px #fff}.jstree-default-dark-responsive>.jstree-striped{background:0 0}.jstree-default-dark-responsive .jstree-wholerow{border-top:1px solid #666;border-bottom:1px solid #000;background:#333;height:40px}.jstree-default-dark-responsive .jstree-wholerow-hovered{background:#555}.jstree-default-dark-responsive .jstree-wholerow-clicked{background:#5fa2db}.jstree-default-dark-responsive .jstree-children .jstree-last>.jstree-wholerow{box-shadow:inset 0 -6px 3px -5px #111}.jstree-default-dark-responsive .jstree-children .jstree-open>.jstree-wholerow{box-shadow:inset 0 6px 3px -5px #111;border-top:0}.jstree-default-dark-responsive .jstree-children .jstree-open+.jstree-open{box-shadow:none}.jstree-default-dark-responsive .jstree-node,.jstree-default-dark-responsive .jstree-icon,.jstree-default-dark-responsive .jstree-node>.jstree-ocl,.jstree-default-dark-responsive .jstree-themeicon,.jstree-default-dark-responsive .jstree-checkbox{background-image:url(40px.png);background-size:120px 240px}.jstree-default-dark-responsive .jstree-node{background-position:-80px 0;background-repeat:repeat-y}.jstree-default-dark-responsive .jstree-last{background:0 0}.jstree-default-dark-responsive .jstree-leaf>.jstree-ocl{background-position:-40px -120px}.jstree-default-dark-responsive .jstree-last>.jstree-ocl{background-position:-40px -160px}.jstree-default-dark-responsive .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default-dark-responsive .jstree-file{background:url(40px.png) 0 -160px no-repeat;background-size:120px 240px}.jstree-default-dark-responsive .jstree-folder{background:url(40px.png) -40px -40px no-repeat;background-size:120px 240px}.jstree-default-dark-responsive>.jstree-container-ul>.jstree-node{margin-left:0;margin-right:0}}.jstree-default-dark{background:#333}.jstree-default-dark .jstree-anchor{color:#999;text-shadow:1px 1px 0 rgba(0,0,0,.5)}.jstree-default-dark .jstree-clicked,.jstree-default-dark .jstree-checked{color:#fff}.jstree-default-dark .jstree-hovered{color:#fff}#jstree-marker.jstree-default-dark{border-left-color:#999;background:0 0}.jstree-default-dark .jstree-anchor>.jstree-icon{opacity:.75}.jstree-default-dark .jstree-clicked>.jstree-icon,.jstree-default-dark .jstree-hovered>.jstree-icon,.jstree-default-dark .jstree-checked>.jstree-icon{opacity:1}.jstree-default-dark.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAACZmZl+9SADAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==)}.jstree-default-dark.jstree-rtl .jstree-last{background:0 0}.jstree-default-dark-small.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAACAQMAAABv1h6PAAAABlBMVEUAAACZmZl+9SADAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMHBgAAiABBI4gz9AAAAABJRU5ErkJggg==)}.jstree-default-dark-small.jstree-rtl .jstree-last{background:0 0}.jstree-default-dark-large.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAACAQMAAAAD0EyKAAAABlBMVEUAAACZmZl+9SADAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjgIIGBgABCgCBvVLXcAAAAABJRU5ErkJggg==)}.jstree-default-dark-large.jstree-rtl .jstree-last{background:0 0}
\ No newline at end of file
diff --git a/htdocs/Libs/jsTree/themes/default-dark/throbber.gif b/htdocs/Libs/jsTree/themes/default-dark/throbber.gif
new file mode 100644
index 0000000..cd75035
--- /dev/null
+++ b/htdocs/Libs/jsTree/themes/default-dark/throbber.gif
Binary files differ
diff --git a/htdocs/Libs/jsTree/themes/default/32px.png b/htdocs/Libs/jsTree/themes/default/32px.png
new file mode 100644
index 0000000..1532715
--- /dev/null
+++ b/htdocs/Libs/jsTree/themes/default/32px.png
Binary files differ
diff --git a/htdocs/Libs/jsTree/themes/default/40px.png b/htdocs/Libs/jsTree/themes/default/40px.png
new file mode 100644
index 0000000..1959347
--- /dev/null
+++ b/htdocs/Libs/jsTree/themes/default/40px.png
Binary files differ
diff --git a/htdocs/Libs/jsTree/themes/default/style.css b/htdocs/Libs/jsTree/themes/default/style.css
new file mode 100644
index 0000000..bf64177
--- /dev/null
+++ b/htdocs/Libs/jsTree/themes/default/style.css
@@ -0,0 +1,1050 @@
+/* jsTree default theme */
+.jstree-node,
+.jstree-children,
+.jstree-container-ul {
+  display: block;
+  margin: 0;
+  padding: 0;
+  list-style-type: none;
+  list-style-image: none;
+}
+.jstree-node {
+  white-space: nowrap;
+}
+.jstree-anchor {
+  display: inline-block;
+  color: black;
+  white-space: nowrap;
+  padding: 0 4px 0 1px;
+  margin: 0;
+  vertical-align: top;
+}
+.jstree-anchor:focus {
+  outline: 0;
+}
+.jstree-anchor,
+.jstree-anchor:link,
+.jstree-anchor:visited,
+.jstree-anchor:hover,
+.jstree-anchor:active {
+  text-decoration: none;
+  color: inherit;
+}
+.jstree-icon {
+  display: inline-block;
+  text-decoration: none;
+  margin: 0;
+  padding: 0;
+  vertical-align: top;
+  text-align: center;
+}
+.jstree-icon:empty {
+  display: inline-block;
+  text-decoration: none;
+  margin: 0;
+  padding: 0;
+  vertical-align: top;
+  text-align: center;
+}
+.jstree-ocl {
+  cursor: pointer;
+}
+.jstree-leaf > .jstree-ocl {
+  cursor: default;
+}
+.jstree .jstree-open > .jstree-children {
+  display: block;
+}
+.jstree .jstree-closed > .jstree-children,
+.jstree .jstree-leaf > .jstree-children {
+  display: none;
+}
+.jstree-anchor > .jstree-themeicon {
+  margin-right: 2px;
+}
+.jstree-no-icons .jstree-themeicon,
+.jstree-anchor > .jstree-themeicon-hidden {
+  display: none;
+}
+.jstree-rtl .jstree-anchor {
+  padding: 0 1px 0 4px;
+}
+.jstree-rtl .jstree-anchor > .jstree-themeicon {
+  margin-left: 2px;
+  margin-right: 0;
+}
+.jstree-rtl .jstree-node {
+  margin-left: 0;
+}
+.jstree-rtl .jstree-container-ul > .jstree-node {
+  margin-right: 0;
+}
+.jstree-wholerow-ul {
+  position: relative;
+  display: inline-block;
+  min-width: 100%;
+}
+.jstree-wholerow-ul .jstree-leaf > .jstree-ocl {
+  cursor: pointer;
+}
+.jstree-wholerow-ul .jstree-anchor,
+.jstree-wholerow-ul .jstree-icon {
+  position: relative;
+}
+.jstree-wholerow-ul .jstree-wholerow {
+  width: 100%;
+  cursor: pointer;
+  position: absolute;
+  left: 0;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+.vakata-context {
+  display: none;
+}
+.vakata-context,
+.vakata-context ul {
+  margin: 0;
+  padding: 2px;
+  position: absolute;
+  background: #f5f5f5;
+  border: 1px solid #979797;
+  -moz-box-shadow: 5px 5px 4px -4px #666666;
+  -webkit-box-shadow: 2px 2px 2px #999999;
+  box-shadow: 2px 2px 2px #999999;
+}
+.vakata-context ul {
+  list-style: none;
+  left: 100%;
+  margin-top: -2.7em;
+  margin-left: -4px;
+}
+.vakata-context .vakata-context-right ul {
+  left: auto;
+  right: 100%;
+  margin-left: auto;
+  margin-right: -4px;
+}
+.vakata-context li {
+  list-style: none;
+  display: inline;
+}
+.vakata-context li > a {
+  display: block;
+  padding: 0 2em 0 2em;
+  text-decoration: none;
+  width: auto;
+  color: black;
+  white-space: nowrap;
+  line-height: 2.4em;
+  -moz-text-shadow: 1px 1px 0 white;
+  -webkit-text-shadow: 1px 1px 0 white;
+  text-shadow: 1px 1px 0 white;
+  -moz-border-radius: 1px;
+  -webkit-border-radius: 1px;
+  border-radius: 1px;
+}
+.vakata-context li > a:hover {
+  position: relative;
+  background-color: #e8eff7;
+  -moz-box-shadow: 0 0 2px #0a6aa1;
+  -webkit-box-shadow: 0 0 2px #0a6aa1;
+  box-shadow: 0 0 2px #0a6aa1;
+}
+.vakata-context li > a.vakata-context-parent {
+  background-image: url("data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAIORI4JlrqN1oMSnmmZDQUAOw==");
+  background-position: right center;
+  background-repeat: no-repeat;
+}
+.vakata-context li > a:focus {
+  outline: 0;
+}
+.vakata-context .vakata-context-hover > a {
+  position: relative;
+  background-color: #e8eff7;
+  -moz-box-shadow: 0 0 2px #0a6aa1;
+  -webkit-box-shadow: 0 0 2px #0a6aa1;
+  box-shadow: 0 0 2px #0a6aa1;
+}
+.vakata-context .vakata-context-separator > a,
+.vakata-context .vakata-context-separator > a:hover {
+  background: white;
+  border: 0;
+  border-top: 1px solid #e2e3e3;
+  height: 1px;
+  min-height: 1px;
+  max-height: 1px;
+  padding: 0;
+  margin: 0 0 0 2.4em;
+  border-left: 1px solid #e0e0e0;
+  -moz-text-shadow: 0 0 0 transparent;
+  -webkit-text-shadow: 0 0 0 transparent;
+  text-shadow: 0 0 0 transparent;
+  -moz-box-shadow: 0 0 0 transparent;
+  -webkit-box-shadow: 0 0 0 transparent;
+  box-shadow: 0 0 0 transparent;
+  -moz-border-radius: 0;
+  -webkit-border-radius: 0;
+  border-radius: 0;
+}
+.vakata-context .vakata-contextmenu-disabled a,
+.vakata-context .vakata-contextmenu-disabled a:hover {
+  color: silver;
+  background-color: transparent;
+  border: 0;
+  box-shadow: 0 0 0;
+}
+.vakata-context li > a > i {
+  text-decoration: none;
+  display: inline-block;
+  width: 2.4em;
+  height: 2.4em;
+  background: transparent;
+  margin: 0 0 0 -2em;
+  vertical-align: top;
+  text-align: center;
+  line-height: 2.4em;
+}
+.vakata-context li > a > i:empty {
+  width: 2.4em;
+  line-height: 2.4em;
+}
+.vakata-context li > a .vakata-contextmenu-sep {
+  display: inline-block;
+  width: 1px;
+  height: 2.4em;
+  background: white;
+  margin: 0 0.5em 0 0;
+  border-left: 1px solid #e2e3e3;
+}
+.vakata-context .vakata-contextmenu-shortcut {
+  font-size: 0.8em;
+  color: silver;
+  opacity: 0.5;
+  display: none;
+}
+.vakata-context-rtl ul {
+  left: auto;
+  right: 100%;
+  margin-left: auto;
+  margin-right: -4px;
+}
+.vakata-context-rtl li > a.vakata-context-parent {
+  background-image: url("data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAINjI+AC7rWHIsPtmoxLAA7");
+  background-position: left center;
+  background-repeat: no-repeat;
+}
+.vakata-context-rtl .vakata-context-separator > a {
+  margin: 0 2.4em 0 0;
+  border-left: 0;
+  border-right: 1px solid #e2e3e3;
+}
+.vakata-context-rtl .vakata-context-left ul {
+  right: auto;
+  left: 100%;
+  margin-left: -4px;
+  margin-right: auto;
+}
+.vakata-context-rtl li > a > i {
+  margin: 0 -2em 0 0;
+}
+.vakata-context-rtl li > a .vakata-contextmenu-sep {
+  margin: 0 0 0 0.5em;
+  border-left-color: white;
+  background: #e2e3e3;
+}
+#jstree-marker {
+  position: absolute;
+  top: 0;
+  left: 0;
+  margin: -5px 0 0 0;
+  padding: 0;
+  border-right: 0;
+  border-top: 5px solid transparent;
+  border-bottom: 5px solid transparent;
+  border-left: 5px solid;
+  width: 0;
+  height: 0;
+  font-size: 0;
+  line-height: 0;
+}
+#jstree-dnd {
+  line-height: 16px;
+  margin: 0;
+  padding: 4px;
+}
+#jstree-dnd .jstree-icon,
+#jstree-dnd .jstree-copy {
+  display: inline-block;
+  text-decoration: none;
+  margin: 0 2px 0 0;
+  padding: 0;
+  width: 16px;
+  height: 16px;
+}
+#jstree-dnd .jstree-ok {
+  background: green;
+}
+#jstree-dnd .jstree-er {
+  background: red;
+}
+#jstree-dnd .jstree-copy {
+  margin: 0 2px 0 2px;
+}
+.jstree-default .jstree-node,
+.jstree-default .jstree-icon {
+  background-repeat: no-repeat;
+  background-color: transparent;
+}
+.jstree-default .jstree-anchor,
+.jstree-default .jstree-wholerow {
+  transition: background-color 0.15s, box-shadow 0.15s;
+}
+.jstree-default .jstree-hovered {
+  background: #e7f4f9;
+  border-radius: 2px;
+  box-shadow: inset 0 0 1px #cccccc;
+}
+.jstree-default .jstree-clicked {
+  background: #beebff;
+  border-radius: 2px;
+  box-shadow: inset 0 0 1px #999999;
+}
+.jstree-default .jstree-no-icons .jstree-anchor > .jstree-themeicon {
+  display: none;
+}
+.jstree-default .jstree-disabled {
+  background: transparent;
+  color: #666666;
+}
+.jstree-default .jstree-disabled.jstree-hovered {
+  background: transparent;
+  box-shadow: none;
+}
+.jstree-default .jstree-disabled.jstree-clicked {
+  background: #efefef;
+}
+.jstree-default .jstree-disabled > .jstree-icon {
+  opacity: 0.8;
+  filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'jstree-grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#jstree-grayscale");
+  /* Firefox 10+ */
+  filter: gray;
+  /* IE6-9 */
+  -webkit-filter: grayscale(100%);
+  /* Chrome 19+ & Safari 6+ */
+}
+.jstree-default .jstree-search {
+  font-style: italic;
+  color: #8b0000;
+  font-weight: bold;
+}
+.jstree-default .jstree-no-checkboxes .jstree-checkbox {
+  display: none !important;
+}
+.jstree-default.jstree-checkbox-no-clicked .jstree-clicked {
+  background: transparent;
+  box-shadow: none;
+}
+.jstree-default.jstree-checkbox-no-clicked .jstree-clicked.jstree-hovered {
+  background: #e7f4f9;
+}
+.jstree-default.jstree-checkbox-no-clicked > .jstree-wholerow-ul .jstree-wholerow-clicked {
+  background: transparent;
+}
+.jstree-default.jstree-checkbox-no-clicked > .jstree-wholerow-ul .jstree-wholerow-clicked.jstree-wholerow-hovered {
+  background: #e7f4f9;
+}
+.jstree-default > .jstree-striped {
+  background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAMAAAB/qqA+AAAABlBMVEUAAAAAAAClZ7nPAAAAAnRSTlMNAMM9s3UAAAAXSURBVHjajcEBAQAAAIKg/H/aCQZ70AUBjAATb6YPDgAAAABJRU5ErkJggg==") left top repeat;
+}
+.jstree-default > .jstree-wholerow-ul .jstree-hovered,
+.jstree-default > .jstree-wholerow-ul .jstree-clicked {
+  background: transparent;
+  box-shadow: none;
+  border-radius: 0;
+}
+.jstree-default .jstree-wholerow {
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+}
+.jstree-default .jstree-wholerow-hovered {
+  background: #e7f4f9;
+}
+.jstree-default .jstree-wholerow-clicked {
+  background: #beebff;
+  background: -moz-linear-gradient(top, #beebff 0%, #a8e4ff 100%);
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #beebff), color-stop(100%, #a8e4ff));
+  background: -webkit-linear-gradient(top, #beebff 0%, #a8e4ff 100%);
+  background: -o-linear-gradient(top, #beebff 0%, #a8e4ff 100%);
+  background: -ms-linear-gradient(top, #beebff 0%, #a8e4ff 100%);
+  background: linear-gradient(to bottom, #beebff 0%, #a8e4ff 100%);
+  /*filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='@color1', endColorstr='@color2',GradientType=0 );*/
+}
+.jstree-default .jstree-node {
+  min-height: 24px;
+  line-height: 24px;
+  margin-left: 24px;
+  min-width: 24px;
+}
+.jstree-default .jstree-anchor {
+  line-height: 24px;
+  height: 24px;
+}
+.jstree-default .jstree-icon {
+  width: 24px;
+  height: 24px;
+  line-height: 24px;
+}
+.jstree-default .jstree-icon:empty {
+  width: 24px;
+  height: 24px;
+  line-height: 24px;
+}
+.jstree-default.jstree-rtl .jstree-node {
+  margin-right: 24px;
+}
+.jstree-default .jstree-wholerow {
+  height: 24px;
+}
+.jstree-default .jstree-node,
+.jstree-default .jstree-icon {
+  background-image: url("32px.png");
+}
+.jstree-default .jstree-node {
+  background-position: -292px -4px;
+  background-repeat: repeat-y;
+}
+.jstree-default .jstree-last {
+  background: transparent;
+}
+.jstree-default .jstree-open > .jstree-ocl {
+  background-position: -132px -4px;
+}
+.jstree-default .jstree-closed > .jstree-ocl {
+  background-position: -100px -4px;
+}
+.jstree-default .jstree-leaf > .jstree-ocl {
+  background-position: -68px -4px;
+}
+.jstree-default .jstree-themeicon {
+  background-position: -260px -4px;
+}
+.jstree-default > .jstree-no-dots .jstree-node,
+.jstree-default > .jstree-no-dots .jstree-leaf > .jstree-ocl {
+  background: transparent;
+}
+.jstree-default > .jstree-no-dots .jstree-open > .jstree-ocl {
+  background-position: -36px -4px;
+}
+.jstree-default > .jstree-no-dots .jstree-closed > .jstree-ocl {
+  background-position: -4px -4px;
+}
+.jstree-default .jstree-disabled {
+  background: transparent;
+}
+.jstree-default .jstree-disabled.jstree-hovered {
+  background: transparent;
+}
+.jstree-default .jstree-disabled.jstree-clicked {
+  background: #efefef;
+}
+.jstree-default .jstree-checkbox {
+  background-position: -164px -4px;
+}
+.jstree-default .jstree-checkbox:hover {
+  background-position: -164px -36px;
+}
+.jstree-default.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox,
+.jstree-default .jstree-checked > .jstree-checkbox {
+  background-position: -228px -4px;
+}
+.jstree-default.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover,
+.jstree-default .jstree-checked > .jstree-checkbox:hover {
+  background-position: -228px -36px;
+}
+.jstree-default .jstree-anchor > .jstree-undetermined {
+  background-position: -196px -4px;
+}
+.jstree-default .jstree-anchor > .jstree-undetermined:hover {
+  background-position: -196px -36px;
+}
+.jstree-default > .jstree-striped {
+  background-size: auto 48px;
+}
+.jstree-default.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==");
+  background-position: 100% 1px;
+  background-repeat: repeat-y;
+}
+.jstree-default.jstree-rtl .jstree-last {
+  background: transparent;
+}
+.jstree-default.jstree-rtl .jstree-open > .jstree-ocl {
+  background-position: -132px -36px;
+}
+.jstree-default.jstree-rtl .jstree-closed > .jstree-ocl {
+  background-position: -100px -36px;
+}
+.jstree-default.jstree-rtl .jstree-leaf > .jstree-ocl {
+  background-position: -68px -36px;
+}
+.jstree-default.jstree-rtl > .jstree-no-dots .jstree-node,
+.jstree-default.jstree-rtl > .jstree-no-dots .jstree-leaf > .jstree-ocl {
+  background: transparent;
+}
+.jstree-default.jstree-rtl > .jstree-no-dots .jstree-open > .jstree-ocl {
+  background-position: -36px -36px;
+}
+.jstree-default.jstree-rtl > .jstree-no-dots .jstree-closed > .jstree-ocl {
+  background-position: -4px -36px;
+}
+.jstree-default .jstree-themeicon-custom {
+  background-color: transparent;
+  background-image: none;
+  background-position: 0 0;
+}
+.jstree-default > .jstree-container-ul .jstree-loading > .jstree-ocl {
+  background: url("throbber.gif") center center no-repeat;
+}
+.jstree-default .jstree-file {
+  background: url("32px.png") -100px -68px no-repeat;
+}
+.jstree-default .jstree-folder {
+  background: url("32px.png") -260px -4px no-repeat;
+}
+.jstree-default > .jstree-container-ul > .jstree-node {
+  margin-left: 0;
+  margin-right: 0;
+}
+#jstree-dnd.jstree-default {
+  line-height: 24px;
+  padding: 0 4px;
+}
+#jstree-dnd.jstree-default .jstree-ok,
+#jstree-dnd.jstree-default .jstree-er {
+  background-image: url("32px.png");
+  background-repeat: no-repeat;
+  background-color: transparent;
+}
+#jstree-dnd.jstree-default i {
+  background: transparent;
+  width: 24px;
+  height: 24px;
+  line-height: 24px;
+}
+#jstree-dnd.jstree-default .jstree-ok {
+  background-position: -4px -68px;
+}
+#jstree-dnd.jstree-default .jstree-er {
+  background-position: -36px -68px;
+}
+.jstree-default.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==");
+}
+.jstree-default.jstree-rtl .jstree-last {
+  background: transparent;
+}
+.jstree-default-small .jstree-node {
+  min-height: 18px;
+  line-height: 18px;
+  margin-left: 18px;
+  min-width: 18px;
+}
+.jstree-default-small .jstree-anchor {
+  line-height: 18px;
+  height: 18px;
+}
+.jstree-default-small .jstree-icon {
+  width: 18px;
+  height: 18px;
+  line-height: 18px;
+}
+.jstree-default-small .jstree-icon:empty {
+  width: 18px;
+  height: 18px;
+  line-height: 18px;
+}
+.jstree-default-small.jstree-rtl .jstree-node {
+  margin-right: 18px;
+}
+.jstree-default-small .jstree-wholerow {
+  height: 18px;
+}
+.jstree-default-small .jstree-node,
+.jstree-default-small .jstree-icon {
+  background-image: url("32px.png");
+}
+.jstree-default-small .jstree-node {
+  background-position: -295px -7px;
+  background-repeat: repeat-y;
+}
+.jstree-default-small .jstree-last {
+  background: transparent;
+}
+.jstree-default-small .jstree-open > .jstree-ocl {
+  background-position: -135px -7px;
+}
+.jstree-default-small .jstree-closed > .jstree-ocl {
+  background-position: -103px -7px;
+}
+.jstree-default-small .jstree-leaf > .jstree-ocl {
+  background-position: -71px -7px;
+}
+.jstree-default-small .jstree-themeicon {
+  background-position: -263px -7px;
+}
+.jstree-default-small > .jstree-no-dots .jstree-node,
+.jstree-default-small > .jstree-no-dots .jstree-leaf > .jstree-ocl {
+  background: transparent;
+}
+.jstree-default-small > .jstree-no-dots .jstree-open > .jstree-ocl {
+  background-position: -39px -7px;
+}
+.jstree-default-small > .jstree-no-dots .jstree-closed > .jstree-ocl {
+  background-position: -7px -7px;
+}
+.jstree-default-small .jstree-disabled {
+  background: transparent;
+}
+.jstree-default-small .jstree-disabled.jstree-hovered {
+  background: transparent;
+}
+.jstree-default-small .jstree-disabled.jstree-clicked {
+  background: #efefef;
+}
+.jstree-default-small .jstree-checkbox {
+  background-position: -167px -7px;
+}
+.jstree-default-small .jstree-checkbox:hover {
+  background-position: -167px -39px;
+}
+.jstree-default-small.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox,
+.jstree-default-small .jstree-checked > .jstree-checkbox {
+  background-position: -231px -7px;
+}
+.jstree-default-small.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover,
+.jstree-default-small .jstree-checked > .jstree-checkbox:hover {
+  background-position: -231px -39px;
+}
+.jstree-default-small .jstree-anchor > .jstree-undetermined {
+  background-position: -199px -7px;
+}
+.jstree-default-small .jstree-anchor > .jstree-undetermined:hover {
+  background-position: -199px -39px;
+}
+.jstree-default-small > .jstree-striped {
+  background-size: auto 36px;
+}
+.jstree-default-small.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==");
+  background-position: 100% 1px;
+  background-repeat: repeat-y;
+}
+.jstree-default-small.jstree-rtl .jstree-last {
+  background: transparent;
+}
+.jstree-default-small.jstree-rtl .jstree-open > .jstree-ocl {
+  background-position: -135px -39px;
+}
+.jstree-default-small.jstree-rtl .jstree-closed > .jstree-ocl {
+  background-position: -103px -39px;
+}
+.jstree-default-small.jstree-rtl .jstree-leaf > .jstree-ocl {
+  background-position: -71px -39px;
+}
+.jstree-default-small.jstree-rtl > .jstree-no-dots .jstree-node,
+.jstree-default-small.jstree-rtl > .jstree-no-dots .jstree-leaf > .jstree-ocl {
+  background: transparent;
+}
+.jstree-default-small.jstree-rtl > .jstree-no-dots .jstree-open > .jstree-ocl {
+  background-position: -39px -39px;
+}
+.jstree-default-small.jstree-rtl > .jstree-no-dots .jstree-closed > .jstree-ocl {
+  background-position: -7px -39px;
+}
+.jstree-default-small .jstree-themeicon-custom {
+  background-color: transparent;
+  background-image: none;
+  background-position: 0 0;
+}
+.jstree-default-small > .jstree-container-ul .jstree-loading > .jstree-ocl {
+  background: url("throbber.gif") center center no-repeat;
+}
+.jstree-default-small .jstree-file {
+  background: url("32px.png") -103px -71px no-repeat;
+}
+.jstree-default-small .jstree-folder {
+  background: url("32px.png") -263px -7px no-repeat;
+}
+.jstree-default-small > .jstree-container-ul > .jstree-node {
+  margin-left: 0;
+  margin-right: 0;
+}
+#jstree-dnd.jstree-default-small {
+  line-height: 18px;
+  padding: 0 4px;
+}
+#jstree-dnd.jstree-default-small .jstree-ok,
+#jstree-dnd.jstree-default-small .jstree-er {
+  background-image: url("32px.png");
+  background-repeat: no-repeat;
+  background-color: transparent;
+}
+#jstree-dnd.jstree-default-small i {
+  background: transparent;
+  width: 18px;
+  height: 18px;
+  line-height: 18px;
+}
+#jstree-dnd.jstree-default-small .jstree-ok {
+  background-position: -7px -71px;
+}
+#jstree-dnd.jstree-default-small .jstree-er {
+  background-position: -39px -71px;
+}
+.jstree-default-small.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAACAQMAAABv1h6PAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMHBgAAiABBI4gz9AAAAABJRU5ErkJggg==");
+}
+.jstree-default-small.jstree-rtl .jstree-last {
+  background: transparent;
+}
+.jstree-default-large .jstree-node {
+  min-height: 32px;
+  line-height: 32px;
+  margin-left: 32px;
+  min-width: 32px;
+}
+.jstree-default-large .jstree-anchor {
+  line-height: 32px;
+  height: 32px;
+}
+.jstree-default-large .jstree-icon {
+  width: 32px;
+  height: 32px;
+  line-height: 32px;
+}
+.jstree-default-large .jstree-icon:empty {
+  width: 32px;
+  height: 32px;
+  line-height: 32px;
+}
+.jstree-default-large.jstree-rtl .jstree-node {
+  margin-right: 32px;
+}
+.jstree-default-large .jstree-wholerow {
+  height: 32px;
+}
+.jstree-default-large .jstree-node,
+.jstree-default-large .jstree-icon {
+  background-image: url("32px.png");
+}
+.jstree-default-large .jstree-node {
+  background-position: -288px 0px;
+  background-repeat: repeat-y;
+}
+.jstree-default-large .jstree-last {
+  background: transparent;
+}
+.jstree-default-large .jstree-open > .jstree-ocl {
+  background-position: -128px 0px;
+}
+.jstree-default-large .jstree-closed > .jstree-ocl {
+  background-position: -96px 0px;
+}
+.jstree-default-large .jstree-leaf > .jstree-ocl {
+  background-position: -64px 0px;
+}
+.jstree-default-large .jstree-themeicon {
+  background-position: -256px 0px;
+}
+.jstree-default-large > .jstree-no-dots .jstree-node,
+.jstree-default-large > .jstree-no-dots .jstree-leaf > .jstree-ocl {
+  background: transparent;
+}
+.jstree-default-large > .jstree-no-dots .jstree-open > .jstree-ocl {
+  background-position: -32px 0px;
+}
+.jstree-default-large > .jstree-no-dots .jstree-closed > .jstree-ocl {
+  background-position: 0px 0px;
+}
+.jstree-default-large .jstree-disabled {
+  background: transparent;
+}
+.jstree-default-large .jstree-disabled.jstree-hovered {
+  background: transparent;
+}
+.jstree-default-large .jstree-disabled.jstree-clicked {
+  background: #efefef;
+}
+.jstree-default-large .jstree-checkbox {
+  background-position: -160px 0px;
+}
+.jstree-default-large .jstree-checkbox:hover {
+  background-position: -160px -32px;
+}
+.jstree-default-large.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox,
+.jstree-default-large .jstree-checked > .jstree-checkbox {
+  background-position: -224px 0px;
+}
+.jstree-default-large.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover,
+.jstree-default-large .jstree-checked > .jstree-checkbox:hover {
+  background-position: -224px -32px;
+}
+.jstree-default-large .jstree-anchor > .jstree-undetermined {
+  background-position: -192px 0px;
+}
+.jstree-default-large .jstree-anchor > .jstree-undetermined:hover {
+  background-position: -192px -32px;
+}
+.jstree-default-large > .jstree-striped {
+  background-size: auto 64px;
+}
+.jstree-default-large.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==");
+  background-position: 100% 1px;
+  background-repeat: repeat-y;
+}
+.jstree-default-large.jstree-rtl .jstree-last {
+  background: transparent;
+}
+.jstree-default-large.jstree-rtl .jstree-open > .jstree-ocl {
+  background-position: -128px -32px;
+}
+.jstree-default-large.jstree-rtl .jstree-closed > .jstree-ocl {
+  background-position: -96px -32px;
+}
+.jstree-default-large.jstree-rtl .jstree-leaf > .jstree-ocl {
+  background-position: -64px -32px;
+}
+.jstree-default-large.jstree-rtl > .jstree-no-dots .jstree-node,
+.jstree-default-large.jstree-rtl > .jstree-no-dots .jstree-leaf > .jstree-ocl {
+  background: transparent;
+}
+.jstree-default-large.jstree-rtl > .jstree-no-dots .jstree-open > .jstree-ocl {
+  background-position: -32px -32px;
+}
+.jstree-default-large.jstree-rtl > .jstree-no-dots .jstree-closed > .jstree-ocl {
+  background-position: 0px -32px;
+}
+.jstree-default-large .jstree-themeicon-custom {
+  background-color: transparent;
+  background-image: none;
+  background-position: 0 0;
+}
+.jstree-default-large > .jstree-container-ul .jstree-loading > .jstree-ocl {
+  background: url("throbber.gif") center center no-repeat;
+}
+.jstree-default-large .jstree-file {
+  background: url("32px.png") -96px -64px no-repeat;
+}
+.jstree-default-large .jstree-folder {
+  background: url("32px.png") -256px 0px no-repeat;
+}
+.jstree-default-large > .jstree-container-ul > .jstree-node {
+  margin-left: 0;
+  margin-right: 0;
+}
+#jstree-dnd.jstree-default-large {
+  line-height: 32px;
+  padding: 0 4px;
+}
+#jstree-dnd.jstree-default-large .jstree-ok,
+#jstree-dnd.jstree-default-large .jstree-er {
+  background-image: url("32px.png");
+  background-repeat: no-repeat;
+  background-color: transparent;
+}
+#jstree-dnd.jstree-default-large i {
+  background: transparent;
+  width: 32px;
+  height: 32px;
+  line-height: 32px;
+}
+#jstree-dnd.jstree-default-large .jstree-ok {
+  background-position: 0px -64px;
+}
+#jstree-dnd.jstree-default-large .jstree-er {
+  background-position: -32px -64px;
+}
+.jstree-default-large.jstree-rtl .jstree-node {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAACAQMAAAAD0EyKAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjgIIGBgABCgCBvVLXcAAAAABJRU5ErkJggg==");
+}
+.jstree-default-large.jstree-rtl .jstree-last {
+  background: transparent;
+}
+@media (max-width: 768px) {
+  #jstree-dnd.jstree-dnd-responsive {
+    line-height: 40px;
+    font-weight: bold;
+    font-size: 1.1em;
+    text-shadow: 1px 1px white;
+  }
+  #jstree-dnd.jstree-dnd-responsive > i {
+    background: transparent;
+    width: 40px;
+    height: 40px;
+  }
+  #jstree-dnd.jstree-dnd-responsive > .jstree-ok {
+    background-image: url("40px.png");
+    background-position: 0 -200px;
+    background-size: 120px 240px;
+  }
+  #jstree-dnd.jstree-dnd-responsive > .jstree-er {
+    background-image: url("40px.png");
+    background-position: -40px -200px;
+    background-size: 120px 240px;
+  }
+  #jstree-marker.jstree-dnd-responsive {
+    border-left-width: 10px;
+    border-top-width: 10px;
+    border-bottom-width: 10px;
+    margin-top: -10px;
+  }
+}
+@media (max-width: 768px) {
+  .jstree-default-responsive {
+    /*
+	.jstree-open > .jstree-ocl,
+	.jstree-closed > .jstree-ocl { border-radius:20px; background-color:white; }
+	*/
+  }
+  .jstree-default-responsive .jstree-icon {
+    background-image: url("40px.png");
+  }
+  .jstree-default-responsive .jstree-node,
+  .jstree-default-responsive .jstree-leaf > .jstree-ocl {
+    background: transparent;
+  }
+  .jstree-default-responsive .jstree-node {
+    min-height: 40px;
+    line-height: 40px;
+    margin-left: 40px;
+    min-width: 40px;
+    white-space: nowrap;
+  }
+  .jstree-default-responsive .jstree-anchor {
+    line-height: 40px;
+    height: 40px;
+  }
+  .jstree-default-responsive .jstree-icon,
+  .jstree-default-responsive .jstree-icon:empty {
+    width: 40px;
+    height: 40px;
+    line-height: 40px;
+  }
+  .jstree-default-responsive > .jstree-container-ul > .jstree-node {
+    margin-left: 0;
+  }
+  .jstree-default-responsive.jstree-rtl .jstree-node {
+    margin-left: 0;
+    margin-right: 40px;
+  }
+  .jstree-default-responsive.jstree-rtl .jstree-container-ul > .jstree-node {
+    margin-right: 0;
+  }
+  .jstree-default-responsive .jstree-ocl,
+  .jstree-default-responsive .jstree-themeicon,
+  .jstree-default-responsive .jstree-checkbox {
+    background-size: 120px 240px;
+  }
+  .jstree-default-responsive .jstree-leaf > .jstree-ocl {
+    background: transparent;
+  }
+  .jstree-default-responsive .jstree-open > .jstree-ocl {
+    background-position: 0 0px !important;
+  }
+  .jstree-default-responsive .jstree-closed > .jstree-ocl {
+    background-position: 0 -40px !important;
+  }
+  .jstree-default-responsive.jstree-rtl .jstree-closed > .jstree-ocl {
+    background-position: -40px 0px !important;
+  }
+  .jstree-default-responsive .jstree-themeicon {
+    background-position: -40px -40px;
+  }
+  .jstree-default-responsive .jstree-checkbox,
+  .jstree-default-responsive .jstree-checkbox:hover {
+    background-position: -40px -80px;
+  }
+  .jstree-default-responsive.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox,
+  .jstree-default-responsive.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover,
+  .jstree-default-responsive .jstree-checked > .jstree-checkbox,
+  .jstree-default-responsive .jstree-checked > .jstree-checkbox:hover {
+    background-position: 0 -80px;
+  }
+  .jstree-default-responsive .jstree-anchor > .jstree-undetermined,
+  .jstree-default-responsive .jstree-anchor > .jstree-undetermined:hover {
+    background-position: 0 -120px;
+  }
+  .jstree-default-responsive .jstree-anchor {
+    font-weight: bold;
+    font-size: 1.1em;
+    text-shadow: 1px 1px white;
+  }
+  .jstree-default-responsive > .jstree-striped {
+    background: transparent;
+  }
+  .jstree-default-responsive .jstree-wholerow {
+    border-top: 1px solid rgba(255, 255, 255, 0.7);
+    border-bottom: 1px solid rgba(64, 64, 64, 0.2);
+    background: #ebebeb;
+    height: 40px;
+  }
+  .jstree-default-responsive .jstree-wholerow-hovered {
+    background: #e7f4f9;
+  }
+  .jstree-default-responsive .jstree-wholerow-clicked {
+    background: #beebff;
+  }
+  .jstree-default-responsive .jstree-children .jstree-last > .jstree-wholerow {
+    box-shadow: inset 0 -6px 3px -5px #666666;
+  }
+  .jstree-default-responsive .jstree-children .jstree-open > .jstree-wholerow {
+    box-shadow: inset 0 6px 3px -5px #666666;
+    border-top: 0;
+  }
+  .jstree-default-responsive .jstree-children .jstree-open + .jstree-open {
+    box-shadow: none;
+  }
+  .jstree-default-responsive .jstree-node,
+  .jstree-default-responsive .jstree-icon,
+  .jstree-default-responsive .jstree-node > .jstree-ocl,
+  .jstree-default-responsive .jstree-themeicon,
+  .jstree-default-responsive .jstree-checkbox {
+    background-image: url("40px.png");
+    background-size: 120px 240px;
+  }
+  .jstree-default-responsive .jstree-node {
+    background-position: -80px 0;
+    background-repeat: repeat-y;
+  }
+  .jstree-default-responsive .jstree-last {
+    background: transparent;
+  }
+  .jstree-default-responsive .jstree-leaf > .jstree-ocl {
+    background-position: -40px -120px;
+  }
+  .jstree-default-responsive .jstree-last > .jstree-ocl {
+    background-position: -40px -160px;
+  }
+  .jstree-default-responsive .jstree-themeicon-custom {
+    background-color: transparent;
+    background-image: none;
+    background-position: 0 0;
+  }
+  .jstree-default-responsive .jstree-file {
+    background: url("40px.png") 0 -160px no-repeat;
+    background-size: 120px 240px;
+  }
+  .jstree-default-responsive .jstree-folder {
+    background: url("40px.png") -40px -40px no-repeat;
+    background-size: 120px 240px;
+  }
+  .jstree-default-responsive > .jstree-container-ul > .jstree-node {
+    margin-left: 0;
+    margin-right: 0;
+  }
+}
diff --git a/htdocs/Libs/jsTree/themes/default/style.min.css b/htdocs/Libs/jsTree/themes/default/style.min.css
new file mode 100644
index 0000000..4440528
--- /dev/null
+++ b/htdocs/Libs/jsTree/themes/default/style.min.css
@@ -0,0 +1 @@
+.jstree-node,.jstree-children,.jstree-container-ul{display:block;margin:0;padding:0;list-style-type:none;list-style-image:none}.jstree-node{white-space:nowrap}.jstree-anchor{display:inline-block;color:#000;white-space:nowrap;padding:0 4px 0 1px;margin:0;vertical-align:top}.jstree-anchor:focus{outline:0}.jstree-anchor,.jstree-anchor:link,.jstree-anchor:visited,.jstree-anchor:hover,.jstree-anchor:active{text-decoration:none;color:inherit}.jstree-icon{display:inline-block;text-decoration:none;margin:0;padding:0;vertical-align:top;text-align:center}.jstree-icon:empty{display:inline-block;text-decoration:none;margin:0;padding:0;vertical-align:top;text-align:center}.jstree-ocl{cursor:pointer}.jstree-leaf>.jstree-ocl{cursor:default}.jstree .jstree-open>.jstree-children{display:block}.jstree .jstree-closed>.jstree-children,.jstree .jstree-leaf>.jstree-children{display:none}.jstree-anchor>.jstree-themeicon{margin-right:2px}.jstree-no-icons .jstree-themeicon,.jstree-anchor>.jstree-themeicon-hidden{display:none}.jstree-rtl .jstree-anchor{padding:0 1px 0 4px}.jstree-rtl .jstree-anchor>.jstree-themeicon{margin-left:2px;margin-right:0}.jstree-rtl .jstree-node{margin-left:0}.jstree-rtl .jstree-container-ul>.jstree-node{margin-right:0}.jstree-wholerow-ul{position:relative;display:inline-block;min-width:100%}.jstree-wholerow-ul .jstree-leaf>.jstree-ocl{cursor:pointer}.jstree-wholerow-ul .jstree-anchor,.jstree-wholerow-ul .jstree-icon{position:relative}.jstree-wholerow-ul .jstree-wholerow{width:100%;cursor:pointer;position:absolute;left:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.vakata-context{display:none}.vakata-context,.vakata-context ul{margin:0;padding:2px;position:absolute;background:#f5f5f5;border:1px solid #979797;-moz-box-shadow:5px 5px 4px -4px #666;-webkit-box-shadow:2px 2px 2px #999;box-shadow:2px 2px 2px #999}.vakata-context ul{list-style:none;left:100%;margin-top:-2.7em;margin-left:-4px}.vakata-context .vakata-context-right ul{left:auto;right:100%;margin-left:auto;margin-right:-4px}.vakata-context li{list-style:none;display:inline}.vakata-context li>a{display:block;padding:0 2em;text-decoration:none;width:auto;color:#000;white-space:nowrap;line-height:2.4em;-moz-text-shadow:1px 1px 0 #fff;-webkit-text-shadow:1px 1px 0 #fff;text-shadow:1px 1px 0 #fff;-moz-border-radius:1px;-webkit-border-radius:1px;border-radius:1px}.vakata-context li>a:hover{position:relative;background-color:#e8eff7;-moz-box-shadow:0 0 2px #0a6aa1;-webkit-box-shadow:0 0 2px #0a6aa1;box-shadow:0 0 2px #0a6aa1}.vakata-context li>a.vakata-context-parent{background-image:url(data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAIORI4JlrqN1oMSnmmZDQUAOw==);background-position:right center;background-repeat:no-repeat}.vakata-context li>a:focus{outline:0}.vakata-context .vakata-context-hover>a{position:relative;background-color:#e8eff7;-moz-box-shadow:0 0 2px #0a6aa1;-webkit-box-shadow:0 0 2px #0a6aa1;box-shadow:0 0 2px #0a6aa1}.vakata-context .vakata-context-separator>a,.vakata-context .vakata-context-separator>a:hover{background:#fff;border:0;border-top:1px solid #e2e3e3;height:1px;min-height:1px;max-height:1px;padding:0;margin:0 0 0 2.4em;border-left:1px solid #e0e0e0;-moz-text-shadow:0 0 0 transparent;-webkit-text-shadow:0 0 0 transparent;text-shadow:0 0 0 transparent;-moz-box-shadow:0 0 0 transparent;-webkit-box-shadow:0 0 0 transparent;box-shadow:0 0 0 transparent;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.vakata-context .vakata-contextmenu-disabled a,.vakata-context .vakata-contextmenu-disabled a:hover{color:silver;background-color:transparent;border:0;box-shadow:0 0 0}.vakata-context li>a>i{text-decoration:none;display:inline-block;width:2.4em;height:2.4em;background:0 0;margin:0 0 0 -2em;vertical-align:top;text-align:center;line-height:2.4em}.vakata-context li>a>i:empty{width:2.4em;line-height:2.4em}.vakata-context li>a .vakata-contextmenu-sep{display:inline-block;width:1px;height:2.4em;background:#fff;margin:0 .5em 0 0;border-left:1px solid #e2e3e3}.vakata-context .vakata-contextmenu-shortcut{font-size:.8em;color:silver;opacity:.5;display:none}.vakata-context-rtl ul{left:auto;right:100%;margin-left:auto;margin-right:-4px}.vakata-context-rtl li>a.vakata-context-parent{background-image:url(data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAINjI+AC7rWHIsPtmoxLAA7);background-position:left center;background-repeat:no-repeat}.vakata-context-rtl .vakata-context-separator>a{margin:0 2.4em 0 0;border-left:0;border-right:1px solid #e2e3e3}.vakata-context-rtl .vakata-context-left ul{right:auto;left:100%;margin-left:-4px;margin-right:auto}.vakata-context-rtl li>a>i{margin:0 -2em 0 0}.vakata-context-rtl li>a .vakata-contextmenu-sep{margin:0 0 0 .5em;border-left-color:#fff;background:#e2e3e3}#jstree-marker{position:absolute;top:0;left:0;margin:-5px 0 0 0;padding:0;border-right:0;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid;width:0;height:0;font-size:0;line-height:0}#jstree-dnd{line-height:16px;margin:0;padding:4px}#jstree-dnd .jstree-icon,#jstree-dnd .jstree-copy{display:inline-block;text-decoration:none;margin:0 2px 0 0;padding:0;width:16px;height:16px}#jstree-dnd .jstree-ok{background:green}#jstree-dnd .jstree-er{background:red}#jstree-dnd .jstree-copy{margin:0 2px}.jstree-default .jstree-node,.jstree-default .jstree-icon{background-repeat:no-repeat;background-color:transparent}.jstree-default .jstree-anchor,.jstree-default .jstree-wholerow{transition:background-color .15s,box-shadow .15s}.jstree-default .jstree-hovered{background:#e7f4f9;border-radius:2px;box-shadow:inset 0 0 1px #ccc}.jstree-default .jstree-clicked{background:#beebff;border-radius:2px;box-shadow:inset 0 0 1px #999}.jstree-default .jstree-no-icons .jstree-anchor>.jstree-themeicon{display:none}.jstree-default .jstree-disabled{background:0 0;color:#666}.jstree-default .jstree-disabled.jstree-hovered{background:0 0;box-shadow:none}.jstree-default .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default .jstree-disabled>.jstree-icon{opacity:.8;filter:url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'jstree-grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#jstree-grayscale");filter:gray;-webkit-filter:grayscale(100%)}.jstree-default .jstree-search{font-style:italic;color:#8b0000;font-weight:700}.jstree-default .jstree-no-checkboxes .jstree-checkbox{display:none!important}.jstree-default.jstree-checkbox-no-clicked .jstree-clicked{background:0 0;box-shadow:none}.jstree-default.jstree-checkbox-no-clicked .jstree-clicked.jstree-hovered{background:#e7f4f9}.jstree-default.jstree-checkbox-no-clicked>.jstree-wholerow-ul .jstree-wholerow-clicked{background:0 0}.jstree-default.jstree-checkbox-no-clicked>.jstree-wholerow-ul .jstree-wholerow-clicked.jstree-wholerow-hovered{background:#e7f4f9}.jstree-default>.jstree-striped{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAMAAAB/qqA+AAAABlBMVEUAAAAAAAClZ7nPAAAAAnRSTlMNAMM9s3UAAAAXSURBVHjajcEBAQAAAIKg/H/aCQZ70AUBjAATb6YPDgAAAABJRU5ErkJggg==) left top repeat}.jstree-default>.jstree-wholerow-ul .jstree-hovered,.jstree-default>.jstree-wholerow-ul .jstree-clicked{background:0 0;box-shadow:none;border-radius:0}.jstree-default .jstree-wholerow{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.jstree-default .jstree-wholerow-hovered{background:#e7f4f9}.jstree-default .jstree-wholerow-clicked{background:#beebff;background:-moz-linear-gradient(top,#beebff 0,#a8e4ff 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#beebff),color-stop(100%,#a8e4ff));background:-webkit-linear-gradient(top,#beebff 0,#a8e4ff 100%);background:-o-linear-gradient(top,#beebff 0,#a8e4ff 100%);background:-ms-linear-gradient(top,#beebff 0,#a8e4ff 100%);background:linear-gradient(to bottom,#beebff 0,#a8e4ff 100%)}.jstree-default .jstree-node{min-height:24px;line-height:24px;margin-left:24px;min-width:24px}.jstree-default .jstree-anchor{line-height:24px;height:24px}.jstree-default .jstree-icon{width:24px;height:24px;line-height:24px}.jstree-default .jstree-icon:empty{width:24px;height:24px;line-height:24px}.jstree-default.jstree-rtl .jstree-node{margin-right:24px}.jstree-default .jstree-wholerow{height:24px}.jstree-default .jstree-node,.jstree-default .jstree-icon{background-image:url(32px.png)}.jstree-default .jstree-node{background-position:-292px -4px;background-repeat:repeat-y}.jstree-default .jstree-last{background:0 0}.jstree-default .jstree-open>.jstree-ocl{background-position:-132px -4px}.jstree-default .jstree-closed>.jstree-ocl{background-position:-100px -4px}.jstree-default .jstree-leaf>.jstree-ocl{background-position:-68px -4px}.jstree-default .jstree-themeicon{background-position:-260px -4px}.jstree-default>.jstree-no-dots .jstree-node,.jstree-default>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-36px -4px}.jstree-default>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-4px -4px}.jstree-default .jstree-disabled{background:0 0}.jstree-default .jstree-disabled.jstree-hovered{background:0 0}.jstree-default .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default .jstree-checkbox{background-position:-164px -4px}.jstree-default .jstree-checkbox:hover{background-position:-164px -36px}.jstree-default.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox,.jstree-default .jstree-checked>.jstree-checkbox{background-position:-228px -4px}.jstree-default.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox:hover,.jstree-default .jstree-checked>.jstree-checkbox:hover{background-position:-228px -36px}.jstree-default .jstree-anchor>.jstree-undetermined{background-position:-196px -4px}.jstree-default .jstree-anchor>.jstree-undetermined:hover{background-position:-196px -36px}.jstree-default>.jstree-striped{background-size:auto 48px}.jstree-default.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==);background-position:100% 1px;background-repeat:repeat-y}.jstree-default.jstree-rtl .jstree-last{background:0 0}.jstree-default.jstree-rtl .jstree-open>.jstree-ocl{background-position:-132px -36px}.jstree-default.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-100px -36px}.jstree-default.jstree-rtl .jstree-leaf>.jstree-ocl{background-position:-68px -36px}.jstree-default.jstree-rtl>.jstree-no-dots .jstree-node,.jstree-default.jstree-rtl>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default.jstree-rtl>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-36px -36px}.jstree-default.jstree-rtl>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-4px -36px}.jstree-default .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default>.jstree-container-ul .jstree-loading>.jstree-ocl{background:url(throbber.gif) center center no-repeat}.jstree-default .jstree-file{background:url(32px.png) -100px -68px no-repeat}.jstree-default .jstree-folder{background:url(32px.png) -260px -4px no-repeat}.jstree-default>.jstree-container-ul>.jstree-node{margin-left:0;margin-right:0}#jstree-dnd.jstree-default{line-height:24px;padding:0 4px}#jstree-dnd.jstree-default .jstree-ok,#jstree-dnd.jstree-default .jstree-er{background-image:url(32px.png);background-repeat:no-repeat;background-color:transparent}#jstree-dnd.jstree-default i{background:0 0;width:24px;height:24px;line-height:24px}#jstree-dnd.jstree-default .jstree-ok{background-position:-4px -68px}#jstree-dnd.jstree-default .jstree-er{background-position:-36px -68px}.jstree-default.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==)}.jstree-default.jstree-rtl .jstree-last{background:0 0}.jstree-default-small .jstree-node{min-height:18px;line-height:18px;margin-left:18px;min-width:18px}.jstree-default-small .jstree-anchor{line-height:18px;height:18px}.jstree-default-small .jstree-icon{width:18px;height:18px;line-height:18px}.jstree-default-small .jstree-icon:empty{width:18px;height:18px;line-height:18px}.jstree-default-small.jstree-rtl .jstree-node{margin-right:18px}.jstree-default-small .jstree-wholerow{height:18px}.jstree-default-small .jstree-node,.jstree-default-small .jstree-icon{background-image:url(32px.png)}.jstree-default-small .jstree-node{background-position:-295px -7px;background-repeat:repeat-y}.jstree-default-small .jstree-last{background:0 0}.jstree-default-small .jstree-open>.jstree-ocl{background-position:-135px -7px}.jstree-default-small .jstree-closed>.jstree-ocl{background-position:-103px -7px}.jstree-default-small .jstree-leaf>.jstree-ocl{background-position:-71px -7px}.jstree-default-small .jstree-themeicon{background-position:-263px -7px}.jstree-default-small>.jstree-no-dots .jstree-node,.jstree-default-small>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-small>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-39px -7px}.jstree-default-small>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-7px -7px}.jstree-default-small .jstree-disabled{background:0 0}.jstree-default-small .jstree-disabled.jstree-hovered{background:0 0}.jstree-default-small .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default-small .jstree-checkbox{background-position:-167px -7px}.jstree-default-small .jstree-checkbox:hover{background-position:-167px -39px}.jstree-default-small.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox,.jstree-default-small .jstree-checked>.jstree-checkbox{background-position:-231px -7px}.jstree-default-small.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox:hover,.jstree-default-small .jstree-checked>.jstree-checkbox:hover{background-position:-231px -39px}.jstree-default-small .jstree-anchor>.jstree-undetermined{background-position:-199px -7px}.jstree-default-small .jstree-anchor>.jstree-undetermined:hover{background-position:-199px -39px}.jstree-default-small>.jstree-striped{background-size:auto 36px}.jstree-default-small.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==);background-position:100% 1px;background-repeat:repeat-y}.jstree-default-small.jstree-rtl .jstree-last{background:0 0}.jstree-default-small.jstree-rtl .jstree-open>.jstree-ocl{background-position:-135px -39px}.jstree-default-small.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-103px -39px}.jstree-default-small.jstree-rtl .jstree-leaf>.jstree-ocl{background-position:-71px -39px}.jstree-default-small.jstree-rtl>.jstree-no-dots .jstree-node,.jstree-default-small.jstree-rtl>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-small.jstree-rtl>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-39px -39px}.jstree-default-small.jstree-rtl>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-7px -39px}.jstree-default-small .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default-small>.jstree-container-ul .jstree-loading>.jstree-ocl{background:url(throbber.gif) center center no-repeat}.jstree-default-small .jstree-file{background:url(32px.png) -103px -71px no-repeat}.jstree-default-small .jstree-folder{background:url(32px.png) -263px -7px no-repeat}.jstree-default-small>.jstree-container-ul>.jstree-node{margin-left:0;margin-right:0}#jstree-dnd.jstree-default-small{line-height:18px;padding:0 4px}#jstree-dnd.jstree-default-small .jstree-ok,#jstree-dnd.jstree-default-small .jstree-er{background-image:url(32px.png);background-repeat:no-repeat;background-color:transparent}#jstree-dnd.jstree-default-small i{background:0 0;width:18px;height:18px;line-height:18px}#jstree-dnd.jstree-default-small .jstree-ok{background-position:-7px -71px}#jstree-dnd.jstree-default-small .jstree-er{background-position:-39px -71px}.jstree-default-small.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAACAQMAAABv1h6PAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMHBgAAiABBI4gz9AAAAABJRU5ErkJggg==)}.jstree-default-small.jstree-rtl .jstree-last{background:0 0}.jstree-default-large .jstree-node{min-height:32px;line-height:32px;margin-left:32px;min-width:32px}.jstree-default-large .jstree-anchor{line-height:32px;height:32px}.jstree-default-large .jstree-icon{width:32px;height:32px;line-height:32px}.jstree-default-large .jstree-icon:empty{width:32px;height:32px;line-height:32px}.jstree-default-large.jstree-rtl .jstree-node{margin-right:32px}.jstree-default-large .jstree-wholerow{height:32px}.jstree-default-large .jstree-node,.jstree-default-large .jstree-icon{background-image:url(32px.png)}.jstree-default-large .jstree-node{background-position:-288px 0;background-repeat:repeat-y}.jstree-default-large .jstree-last{background:0 0}.jstree-default-large .jstree-open>.jstree-ocl{background-position:-128px 0}.jstree-default-large .jstree-closed>.jstree-ocl{background-position:-96px 0}.jstree-default-large .jstree-leaf>.jstree-ocl{background-position:-64px 0}.jstree-default-large .jstree-themeicon{background-position:-256px 0}.jstree-default-large>.jstree-no-dots .jstree-node,.jstree-default-large>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-large>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-32px 0}.jstree-default-large>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:0 0}.jstree-default-large .jstree-disabled{background:0 0}.jstree-default-large .jstree-disabled.jstree-hovered{background:0 0}.jstree-default-large .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default-large .jstree-checkbox{background-position:-160px 0}.jstree-default-large .jstree-checkbox:hover{background-position:-160px -32px}.jstree-default-large.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox,.jstree-default-large .jstree-checked>.jstree-checkbox{background-position:-224px 0}.jstree-default-large.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox:hover,.jstree-default-large .jstree-checked>.jstree-checkbox:hover{background-position:-224px -32px}.jstree-default-large .jstree-anchor>.jstree-undetermined{background-position:-192px 0}.jstree-default-large .jstree-anchor>.jstree-undetermined:hover{background-position:-192px -32px}.jstree-default-large>.jstree-striped{background-size:auto 64px}.jstree-default-large.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==);background-position:100% 1px;background-repeat:repeat-y}.jstree-default-large.jstree-rtl .jstree-last{background:0 0}.jstree-default-large.jstree-rtl .jstree-open>.jstree-ocl{background-position:-128px -32px}.jstree-default-large.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-96px -32px}.jstree-default-large.jstree-rtl .jstree-leaf>.jstree-ocl{background-position:-64px -32px}.jstree-default-large.jstree-rtl>.jstree-no-dots .jstree-node,.jstree-default-large.jstree-rtl>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-large.jstree-rtl>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-32px -32px}.jstree-default-large.jstree-rtl>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:0 -32px}.jstree-default-large .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default-large>.jstree-container-ul .jstree-loading>.jstree-ocl{background:url(throbber.gif) center center no-repeat}.jstree-default-large .jstree-file{background:url(32px.png) -96px -64px no-repeat}.jstree-default-large .jstree-folder{background:url(32px.png) -256px 0 no-repeat}.jstree-default-large>.jstree-container-ul>.jstree-node{margin-left:0;margin-right:0}#jstree-dnd.jstree-default-large{line-height:32px;padding:0 4px}#jstree-dnd.jstree-default-large .jstree-ok,#jstree-dnd.jstree-default-large .jstree-er{background-image:url(32px.png);background-repeat:no-repeat;background-color:transparent}#jstree-dnd.jstree-default-large i{background:0 0;width:32px;height:32px;line-height:32px}#jstree-dnd.jstree-default-large .jstree-ok{background-position:0 -64px}#jstree-dnd.jstree-default-large .jstree-er{background-position:-32px -64px}.jstree-default-large.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAACAQMAAAAD0EyKAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjgIIGBgABCgCBvVLXcAAAAABJRU5ErkJggg==)}.jstree-default-large.jstree-rtl .jstree-last{background:0 0}@media (max-width:768px){#jstree-dnd.jstree-dnd-responsive{line-height:40px;font-weight:700;font-size:1.1em;text-shadow:1px 1px #fff}#jstree-dnd.jstree-dnd-responsive>i{background:0 0;width:40px;height:40px}#jstree-dnd.jstree-dnd-responsive>.jstree-ok{background-image:url(40px.png);background-position:0 -200px;background-size:120px 240px}#jstree-dnd.jstree-dnd-responsive>.jstree-er{background-image:url(40px.png);background-position:-40px -200px;background-size:120px 240px}#jstree-marker.jstree-dnd-responsive{border-left-width:10px;border-top-width:10px;border-bottom-width:10px;margin-top:-10px}}@media (max-width:768px){.jstree-default-responsive .jstree-icon{background-image:url(40px.png)}.jstree-default-responsive .jstree-node,.jstree-default-responsive .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-responsive .jstree-node{min-height:40px;line-height:40px;margin-left:40px;min-width:40px;white-space:nowrap}.jstree-default-responsive .jstree-anchor{line-height:40px;height:40px}.jstree-default-responsive .jstree-icon,.jstree-default-responsive .jstree-icon:empty{width:40px;height:40px;line-height:40px}.jstree-default-responsive>.jstree-container-ul>.jstree-node{margin-left:0}.jstree-default-responsive.jstree-rtl .jstree-node{margin-left:0;margin-right:40px}.jstree-default-responsive.jstree-rtl .jstree-container-ul>.jstree-node{margin-right:0}.jstree-default-responsive .jstree-ocl,.jstree-default-responsive .jstree-themeicon,.jstree-default-responsive .jstree-checkbox{background-size:120px 240px}.jstree-default-responsive .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-responsive .jstree-open>.jstree-ocl{background-position:0 0!important}.jstree-default-responsive .jstree-closed>.jstree-ocl{background-position:0 -40px!important}.jstree-default-responsive.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-40px 0!important}.jstree-default-responsive .jstree-themeicon{background-position:-40px -40px}.jstree-default-responsive .jstree-checkbox,.jstree-default-responsive .jstree-checkbox:hover{background-position:-40px -80px}.jstree-default-responsive.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox,.jstree-default-responsive.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox:hover,.jstree-default-responsive .jstree-checked>.jstree-checkbox,.jstree-default-responsive .jstree-checked>.jstree-checkbox:hover{background-position:0 -80px}.jstree-default-responsive .jstree-anchor>.jstree-undetermined,.jstree-default-responsive .jstree-anchor>.jstree-undetermined:hover{background-position:0 -120px}.jstree-default-responsive .jstree-anchor{font-weight:700;font-size:1.1em;text-shadow:1px 1px #fff}.jstree-default-responsive>.jstree-striped{background:0 0}.jstree-default-responsive .jstree-wholerow{border-top:1px solid rgba(255,255,255,.7);border-bottom:1px solid rgba(64,64,64,.2);background:#ebebeb;height:40px}.jstree-default-responsive .jstree-wholerow-hovered{background:#e7f4f9}.jstree-default-responsive .jstree-wholerow-clicked{background:#beebff}.jstree-default-responsive .jstree-children .jstree-last>.jstree-wholerow{box-shadow:inset 0 -6px 3px -5px #666}.jstree-default-responsive .jstree-children .jstree-open>.jstree-wholerow{box-shadow:inset 0 6px 3px -5px #666;border-top:0}.jstree-default-responsive .jstree-children .jstree-open+.jstree-open{box-shadow:none}.jstree-default-responsive .jstree-node,.jstree-default-responsive .jstree-icon,.jstree-default-responsive .jstree-node>.jstree-ocl,.jstree-default-responsive .jstree-themeicon,.jstree-default-responsive .jstree-checkbox{background-image:url(40px.png);background-size:120px 240px}.jstree-default-responsive .jstree-node{background-position:-80px 0;background-repeat:repeat-y}.jstree-default-responsive .jstree-last{background:0 0}.jstree-default-responsive .jstree-leaf>.jstree-ocl{background-position:-40px -120px}.jstree-default-responsive .jstree-last>.jstree-ocl{background-position:-40px -160px}.jstree-default-responsive .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default-responsive .jstree-file{background:url(40px.png) 0 -160px no-repeat;background-size:120px 240px}.jstree-default-responsive .jstree-folder{background:url(40px.png) -40px -40px no-repeat;background-size:120px 240px}.jstree-default-responsive>.jstree-container-ul>.jstree-node{margin-left:0;margin-right:0}}
\ No newline at end of file
diff --git a/htdocs/Libs/jsTree/themes/default/throbber.gif b/htdocs/Libs/jsTree/themes/default/throbber.gif
new file mode 100644
index 0000000..1b5b2fd
--- /dev/null
+++ b/htdocs/Libs/jsTree/themes/default/throbber.gif
Binary files differ
diff --git a/htdocs/Main.html b/htdocs/Main.html
new file mode 100644
index 0000000..56966c4
--- /dev/null
+++ b/htdocs/Main.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<!--Copyright (c) 2000-2017 Ericsson Telecom AB
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+which accompanies this distribution, and is available at
+http:www.eclipse.org/legal/epl-v10.html                           --> 
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+        <meta charset="UTF-8">
+
+        <!-- CSS -->
+        <link rel="stylesheet" type="text/css" href="WebApplicationFramework/Res/Main.css" />
+        <!--link rel="stylesheet" type="text/css" href="Libs/JQueryUI/themes/cupertino/jquery-ui.min.css" /-->
+        <link rel="stylesheet" type="text/css" href="Libs/JQueryUI/jquery-ui.css" />
+        <!--link rel="stylesheet" type="text/css" href="Libs/JQueryUI/jquery-ui.structure.css" /-->
+        <!--link rel="stylesheet" type="text/css" href="Libs/JQueryUI/jquery-ui.theme.css" /-->
+        <link rel="stylesheet" type="text/css" href="Libs/jsTree/themes/default/style.min.css" />
+        <link rel="stylesheet" type="text/css" href="Libs/Codemirror/codemirror.css" />
+
+        <!-- GENERAL LIBS -->
+        <script src="Utils/Polyfill.js"></script>
+        <script src="Utils/Compat.js"></script>
+        <!-- Polyfill the Zeroth, for the old browsers. -->
+        <script src="Libs/JQuery/jquery-2.2.3.min.js"></script>
+        <script src="Libs/JQuery/jquery.svg.js"></script>
+        <script src="Libs/jsTree/jstree.min.js"></script>
+        <script src="Libs/JQueryUI/jquery-ui.js "></script>
+        <script src="Libs/AJV/ajv.min.js"></script>
+        <script src="Libs/Html2Canvas/html2canvas.js"></script>
+        <script src="Libs/Flot/jquery.flot.min.js"></script>
+        <script src="Libs/Flot/jquery.flot.time.js"></script>
+        <script src="Libs/Flot/jquery.flot.resize.min.js"></script>
+        <script src="Libs/Flot/jquery.flot.navigate.min.js"></script>
+        <!-- Customized libs -->
+        <script src="Libs/JSONEditor/jsoneditor.custom.js"></script>
+        <script src="Libs/Codemirror/codemirror.custom.js"></script>
+
+        <!-- GENERAL UTILITIES -->
+        <script src="Utils/Utilities.js"></script>
+        <script src="Utils/LineDrawer.js"></script>
+        <script src="Utils/FileHandler.js"></script>
+        <script src="Utils/TaskUtils.js"></script>
+        <script src="Utils/JsonLoader.js"></script>
+        <script src="Utils/FileLoader.js"></script>
+        <script src="Utils/DataSourceUtils.js"></script>
+        <script src="Utils/JsTreeUtils.js"></script>
+        <script src="Utils/ViewUtils.js"></script>
+        <script src="Utils/RequestBuilderFromHelp_full.js"></script>
+        <script src="Utils/RequestBuilderFromHelp_manual.js"></script>
+        <script src="Utils/HelpTreeBuilder.js"></script>
+
+        <!-- MAIN SCRIPTS -->
+        <script src="WebApplicationFramework/FrameworkMain.js"></script>
+        <script src="WebApplicationFramework/Setup_Model.js"></script>
+        <script src="WebApplicationFramework/WebApp_Model.js"></script>
+
+        <title>TitanSim RnXnn</title>
+    </head>
+    <body>
+        <div id="TSGuiFrameworkMain">
+            <div id="applications_header_container">
+                <!--div class="line"></div-->
+                <div id="applications_header" class="applications_header_class">
+                    <!-- toggle for hidden applications, connected code can also be found in FrameworkMain.js and Main.css -->
+                    <!--div id="webappToggle"><button id="webappToggleButton"><span><img src="WebApplicationFramework/Res/grip_gray.png"/></span></button></div>
+                    <div id="hiddenWebapps" class="hidden"></div-->
+                    <div id="webapps"></div>
+                    <div id="eriHdr"><span><img class="margin_logo" src="WebApplicationFramework/Res/ericsson.png"/>TitanSim RnXnn</span></div>
+                </div>
+                <div class="line"></div>
+            </div>
+        </div>
+    </body>
+</html>
diff --git a/htdocs/Utils/Compat.js b/htdocs/Utils/Compat.js
new file mode 100644
index 0000000..839fa5a
--- /dev/null
+++ b/htdocs/Utils/Compat.js
@@ -0,0 +1,27 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+"use strict";

+

+/* oldff means firefox < 4.0, which has a buggy SVG support and missing a lot of features, which sucks. */

+var oldff = /Firefox\/([1-3])\./i.test(navigator.userAgent);

+/* isIE10 means exactly IE10, which has a buggy SVG support and crashes the renderer(== not drawing anything) if markers are applied dynamically, which sucks. */

+var isIE10 = false; // Will be changed by IE-specific Conditional Compilation. JS minification will corrupt this!!!

+/*@cc_on

+    if (/^10/.test(@_jscript_version)) {

+        isIE10 = true;

+    }

+@*/

+var isIE11 = !(window.ActiveXObject) && "ActiveXObject" in window;

+

+function browserCheck() {

+    var N= navigator.appName, ua= navigator.userAgent, tem;

+    var M= ua.match(/(opera|chrome|safari|firefox|msie|trident)\/?\s*(\.?\d+(\.\d+)*)/i);

+    if(M && (tem= ua.match(/version\/([\.\d]+)/i))!= null) {M[2]=tem[1];}

+    M= M? [M[1], M[2]]: [N, navigator.appVersion,'-?'];

+    return M;

+}

+

+//# sourceURL=Utils\Compat.js
\ No newline at end of file
diff --git a/htdocs/Utils/DataSourceUtils.js b/htdocs/Utils/DataSourceUtils.js
new file mode 100644
index 0000000..3e7fbd3
--- /dev/null
+++ b/htdocs/Utils/DataSourceUtils.js
@@ -0,0 +1,458 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function DataSourceUtils() {

+    "use strict";

+    

+    var v_this = this;

+    

+    this.convertHelpToTreeDataArray = function(p_help, p_elementIcon) {

+        var v_contents = [];

+        var info;

+

+        for (var i = 0; i < p_help.length; i++) {

+            var v_childrens = [];

+            var v_row = {};

+

+            if (p_help[i].dataElement != undefined) {

+                v_row.text = p_help[i].dataElement.name;

+                if (p_elementIcon)

+                    v_row.icon = p_elementIcon;

+            }

+            else {

+                v_row.text = p_help[i].source;

+            }

+

+            if (p_help[i].dataElement != undefined) {

+                info = JSON.stringify(p_help[i].dataElement, null, 4);

+                info = replaceAll(info , '\\"', "'");

+                info = replaceAll(info , '"', "'");

+            } else {

+                info = "No description";

+            }

+            v_row.data = info;

+            

+            if (p_help[i].children != undefined && p_help[i].children.length > 0) {

+                v_childrens = this.convertHelpToTreeDataArray(p_help[i].children, p_elementIcon);

+            } else if (p_help[i].dataElements != undefined && p_help[i].dataElements.length > 0) {

+                v_childrens = this.convertHelpToTreeDataArray(p_help[i].dataElements, p_elementIcon);

+            }

+            v_row.children = v_childrens;

+            v_contents.push(v_row);

+        }

+        return v_contents;

+    };    

+

+    this.convertRequestToTreeDataArray = function(a_request) {

+        var v_content = [];

+

+        for (var i = 0; i < a_request.length; i++) {

+            var v_childrens = [];

+            var v_row = {};

+            

+            var setOrGetData;

+            if (a_request[i].getData)

+                setOrGetData = "getData";

+            else if (a_request[i].setData)

+                setOrGetData = "setData";

+            if (setOrGetData && a_request[i][setOrGetData] && a_request[i][setOrGetData].children != undefined && a_request[i][setOrGetData].children.length > 0) {

+                v_childrens = this.convertRequestToTreeDataArray(a_request[i][setOrGetData].children);

+            }

+            if (a_request[i][setOrGetData])

+                v_row.text = a_request[i][setOrGetData].element;

+

+            if (v_childrens.length > 0) {

+                v_row.children = v_childrens;

+            }

+            v_content.push(v_row);

+        }

+        return v_content;

+    };    

+    

+    this.dataSkeletonEquals = function(response1, response2) {

+        if (response1 == undefined && response2 == undefined)

+            return true;

+        else if ((response1 == undefined && response2 != undefined) || (response2 == undefined && response1 != undefined))

+            return false;

+        else if (response1.node != undefined && response2.node != undefined)

+        {

+            if ((response1.node.childVals == undefined) && (response2.node.childVals == undefined))

+                return true;

+            else if ((response1.node.childVals != undefined) && (response2.node.childVals != undefined))

+            {

+                if (response1.node.childVals.length !== response2.node.childVals.length)

+                    return false;            

+                for (var i = 0; i < response1.node.childVals.length; i++)

+                    if (!this.dataSkeletonEquals(response1.node.childVals[i], response2.node.childVals[i]))

+                        return false;

+                return true;

+            }

+            else

+                return false;

+        }

+        else if (response1.list != undefined && response2.list != undefined)

+        {

+            if (response1.list.length !== response2.list.length)

+                return false;

+            for (var j = 0; j < response1.list.length; j++)

+                if (!this.dataSkeletonEquals(response1.list[j], response2.list[j]))

+                    return false;

+            return true;

+        }

+        else if (response1.length != undefined)

+        {

+            if (response2.length == undefined)

+                return false;

+            if (response1.length !== response2.length)

+                return false;

+            for (var k = 0; k < response1.length; k++)

+                if (!this.dataSkeletonEquals(response1[k], response2[k]))

+                    return false;

+            return true;

+        }

+        else

+            return false;

+    };

+    

+    this.expandResponse = function(a_response, a_nestingLevel, a_parentList, a_parentIndexes, a_request, aIdxInList) {

+        var lParentList;

+        var lParentIndexes;

+        if (a_response)

+        {

+            if (a_response.length != undefined) // childVals or root list

+            {

+                if (a_request == undefined || a_response.length != a_request.length) {

+                    return false;

+                }

+                for (var i = 0; i < a_response.length; i++)

+                {

+                    lParentList = [];

+                    for (var j = 0; j < a_parentList.length; j++)

+                        lParentList[j] = a_parentList[j];

+                    lParentIndexes = mcopy(a_parentIndexes);

+                    if (a_request)

+                        if (!this.expandResponse(a_response[i], a_nestingLevel + 1, lParentList, lParentIndexes, a_request[i])) {

+                            return false;

+                        }

+                }

+            }

+            else if (a_response.node != undefined && a_request != undefined)

+            {

+                var getOrSetData;

+                if (a_request.getData != undefined) {

+                    getOrSetData = "getData";

+                } else if (a_request.setData != undefined) {

+                    getOrSetData = "setData";

+                } else {

+                    return false;

+                }

+                a_response.getData = {};

+                a_response.getData.tp = a_response.node.tp;

+                a_response.getData.source = a_request[getOrSetData].source;

+                a_response.getData.element = a_request[getOrSetData].element;

+                if (a_request[getOrSetData].ptcname != undefined)

+                    a_response.getData.ptcname = a_request[getOrSetData].ptcname;

+                if (a_request[getOrSetData].params != undefined)

+                {

+                    a_response.getData.params = [];

+                    for (var j = 0; j < a_request[getOrSetData].params.length; j++)

+                    {

+                        a_response.getData.params[j] = {};

+                        a_response.getData.params[j].paramName = a_request[getOrSetData].params[j].paramName;

+                        a_response.getData.params[j].paramValue = a_request[getOrSetData].params[j].paramValue;

+                    }

+                }

+                a_response.getData.idxInList = aIdxInList;

+                a_parentList[a_parentList.length] = a_response.node.val;

+                a_parentIndexes[a_parentIndexes.length] = aIdxInList;

+                completeGetDataParameters(a_response.getData, a_parentList, a_parentIndexes);

+                if (a_response.node.childVals != undefined) {

+                    var ans = this.expandResponse(a_response.node.childVals, a_nestingLevel, a_parentList, a_parentIndexes, a_request[getOrSetData].children);

+                    if (!ans) {

+                        return false;

+                    } else {

+                        a_response.node.childVals = ans;

+                    }

+                } else {

+                    if (a_response.node.tp != 0 && a_request[getOrSetData].children != undefined && a_request[getOrSetData].children.length != 0 && (a_request[getOrSetData].selection == undefined ||  aIdxInList == a_request[getOrSetData].selection[0])) {

+                        return false;

+                    }

+                }

+                a_response.getData.origRq = a_request[getOrSetData];

+            }

+            else if (a_response.list != undefined)

+            {

+                for (var i = 0; i < a_response.list.length; i++)

+                {

+                    lParentList = [];

+                    for (var j = 0; j < a_parentList.length; j++)

+                        lParentList[j] = a_parentList[j];

+                    lParentIndexes = mcopy(a_parentIndexes);

+                    if (!this.expandResponse(a_response.list[i], a_nestingLevel + 1, lParentList, lParentIndexes, a_request, i)) {

+                        return false;

+                    }

+                }

+            }

+            else

+            {

+                return false;

+            }

+        }

+        return a_response;

+    };

+    

+    this.isResponseToRequest = function(p_contentList, p_requests) {

+        if (p_contentList.length != p_requests.length) {

+            // at least one response is missing

+            return false;

+        }

+        

+        for (var i = 0; i < p_requests.length; ++i) {

+            var request = p_requests[i].getData;

+            var response = p_contentList[i];

+            if (response.node != undefined) {

+                if (request.children != undefined && response.node.childVals != undefined) {

+                    if (!this.isResponseToRequest(response.node.childVals, request.children)) {

+                        return false;

+                    }

+                }

+                if (request.children != undefined && request.children.length > 0 && (response.node.childVals == undefined || response.node.childVals.length == 0) && request.filter == undefined) {

+                    // the response is a node, the request has children and no filter but the response does not have childVals

+                    return false;

+                } else if (response.node.childVals != undefined && response.node.childVals.length != 0 && (request.children == undefined || request.children.length == 0)) {

+                    // the response has childVals but the request does not have children

+                    return false;

+                }

+            } else if (response.list != undefined) {

+                if (request.selectionValues != undefined && request.selectionValues[0] != undefined && response.list[0] != undefined && request.selectionValues[0] != response.list[0].node.val) {

+                    // response is a lisr, request has selection value but the response is different

+                    return false;

+                }

+                

+                for (var j = 0; j < response.list.length; ++j) {

+                    var responseNode = response.list[j];

+                    if (responseNode.node.childVals != undefined && responseNode.node.childVals.length > 0) {

+                        if (request.children == undefined || request.children.length == 0) {

+                            // response has childVals but the request does not have children

+                            return false;

+                        }

+                        

+                        if (request.selectionValues != undefined) {

+                            if (j > 0) {

+                                // request has selection values and a response other than the first has childVals

+                                return false;

+                            }

+                        } else if (request.selection != undefined) {

+                            if (request.selection[0] != j) {

+                                // request has selection and a response other than the one specified by the selection has childVals

+                                return false;

+                            }

+                        }

+                        

+                        if (!this.isResponseToRequest(responseNode.node.childVals, request.children)) {

+                            return false;

+                        }

+                    }

+                }

+            } else {

+                // response is not a node and not a list

+                return false;

+            }

+        }

+        

+        return true;

+    }

+    

+    /*

+    // childVals or root response, children or root requests

+    this.expandResponse = function(p_contentList, p_requests, p_parentList) {

+        if (p_contentList != undefined) {

+            for (var i = 0; i < p_requests.length; ++i) {

+                expand(p_contentList[i], p_requests[i], p_parentList);

+            }

+        }

+        return p_contentList;

+    };

+    

+    function expand(p_content, p_request, p_parentList) {

+        if (p_content != undefined && p_content.node != undefined) {

+            addRequestToResponse(p_content, p_request, undefined, p_parentList);

+            if (p_request.getData != undefined && p_request.getData.children != undefined) {

+                p_parentList.push(p_content.node.val);

+                v_this.expandResponse(p_content.node.childVals, p_request.getData.children, p_parentList);

+                p_parentList.pop();

+            }

+        } else if (p_content != undefined && p_content.list != undefined) {

+            for (var i = 0; i < p_content.list.length; ++i) {

+                addRequestToResponse(p_content.list[i], p_request, i, p_parentList);

+                if (p_request.getData != undefined && p_request.getData.children != undefined) {

+                    p_parentList.push(p_content.list[i].node.val);

+                    v_this.expandResponse(p_content.list[i].node.childVals, p_request.getData.children, p_parentList);

+                    p_parentList.pop();

+                }

+            }

+        }

+    }

+    

+    function addRequestToResponse(p_node, p_request, p_indexInList, p_parentList) {

+        var getOrSetData;

+        if (p_request.getData != undefined) {

+            getOrSetData = p_request.getData;

+        } else if (p_request.setData != undefined) {

+            getOrSetData = p_request.setData;

+        } else {

+            return;

+        }

+        

+        p_node.getData = {};

+        p_node.getData.tp = p_node.node.tp;

+        p_node.getData.source = getOrSetData.source;

+        p_node.getData.element = getOrSetData.element;

+        p_node.getData.ptcname = getOrSetData.ptcname;

+        if (getOrSetData.params != undefined) {

+            p_node.getData.params = [];

+            for (var i = 0; i < getOrSetData.params.length; i++) {

+                p_node.getData.params[i] = {};

+                p_node.getData.params[i].paramName = getOrSetData.params[i].paramName;

+                p_node.getData.params[i].paramValue = getOrSetData.params[i].paramValue;

+            }

+        }

+        p_node.getData.idxInList = p_indexInList;

+        p_node.getData.origRq = getOrSetData;

+        completeGetDataParameters(p_node.getData, p_parentList);

+    }

+    */

+    

+    function completeGetDataParameters(pl_getData, pl_parentList, pl_parentIndexes) {

+        function replaceTemplate(pl_replaceTemplate, pl_replaceWith) {

+            if (pl_getData.source === pl_replaceTemplate)

+                pl_getData.source = pl_replaceWith;

+            if (pl_getData.element === pl_replaceTemplate)

+                pl_getData.element = pl_replaceWith;

+            if (pl_getData.ptcname === pl_replaceTemplate)

+                pl_getData.ptcname = pl_replaceWith;

+            if (pl_getData.params != undefined)

+                for (var i = 0; i < pl_getData.params.length; i++)

+                    if (pl_getData.params[i].paramValue === pl_replaceTemplate)

+                        pl_getData.params[i].paramValue = pl_replaceWith;

+        }

+        

+        for (var vl_i = 0; vl_i < pl_parentList.length; vl_i++) {

+            replaceTemplate("%Parent" + vl_i + "%", pl_parentList[vl_i]);

+            replaceTemplate("%Parent" + vl_i + "::idx%", "" + pl_parentIndexes[vl_i]);

+        }

+    }

+        

+    this.setValue = function(requestList, contentList, path, indexInList, value, additionalSelections) {

+        var nextSelectionIndex = 0;

+        var parents = [];

+        var parentIndexes = [];

+        var request;

+        var response;

+        

+        for (var i = 0; i < path.length; ++i) {

+            if (requestList == undefined || contentList == undefined || requestList[path[i]] == undefined || contentList[path[i]] == undefined) {

+                // the response or the request has no more children, but the path points below the current element

+                return undefined;

+            }

+            

+            request = requestList[path[i]];

+            response = contentList[path[i]];

+            

+            if (response.node != undefined) {

+                parents.push(response.node.val);

+                parentIndexes.push(0);

+            } else if (response.list != undefined) {

+                if (request.getData.selectionValues != undefined && request.getData.selectionValues[0] != undefined) {

+                    response = response.list[0];

+                    if (response == undefined) {

+                        // the response list is not long enough

+                        return undefined;

+                    }

+                    parents.push(response.node.val);

+                    parentIndexes.push(request.getData.selection[0]);

+                } else if (request.getData.selection != undefined && request.getData.selection[0] != undefined) {

+                    response = response.list[request.getData.selection[0]];

+                    if (response == undefined) {

+                        return undefined;

+                    }

+                    parents.push(response.node.val);

+                    parentIndexes.push(request.getData.selection[0]);

+                } else if (additionalSelections != undefined && additionalSelections[nextSelectionIndex] != undefined) {

+                    response = response.list[additionalSelections[nextSelectionIndex]];

+                    if (response == undefined) {

+                        return undefined;

+                    }

+                    parents.push(response.node.val);

+                    parentIndexes.push(additionalSelections[nextSelectionIndex]);

+                    ++nextSelectionIndex;

+                } else {

+                    if (i == path.length - 1) {

+                        // this is the last element and we might be setting a list in which case we do not need to go further

+                        break;

+                    } else {

+                        // we could not find out the index of the element below which the path points 

+                        return undefined;

+                    }

+                }

+            }

+            

+            requestList = request.getData.children;

+            contentList = response.node.childVals;

+        }

+        

+        if (request != undefined && response != undefined) {

+            return createSetData(request, response, parents, parentIndexes, indexInList, value);

+        } else {

+            return undefined;

+        }

+    };

+    

+    function createSetData(request, response, parents, parentIndexes, indexInList, value) {

+        var setData = {"setData": {}};

+        setData.setData.source = request.getData.source;

+        setData.setData.element = request.getData.element;

+        setData.setData.ptcname = request.getData.ptcname;

+        if (indexInList != undefined) {

+            setData.setData.indxsInList = [indexInList];

+        }

+        setData.setData.content = value;

+        if (request.getData.params != undefined) {

+            setData.setData.params = mcopy(request.getData.params);

+        }

+        if (response.node != undefined) {

+            setData.setData.tp = response.node.tp;

+        } else if (response.list != undefined) {

+            setData.setData.tp = response.list[0].node.tp;

+        } else {

+            return undefined

+        }

+        

+        for (var i = 0; i < parents.length; ++i) {

+            completeParams(setData.setData, parents, parentIndexes, i);

+        }

+        

+        return setData;

+    }

+    

+    function completeParams(setData, parents, parentIndexes, i) {

+        var patternForParent = new RegExp("%Parent" + i + "%");

+        var patternForParentIndex = new RegExp("%Parent" + i + "::idx%");

+        setData.source = setData.source.replace(patternForParentIndex, parentIndexes[i]);

+        setData.source = setData.source.replace(patternForParent, parents[i]);

+        setData.element = setData.element.replace(patternForParentIndex, parentIndexes[i]);

+        setData.element = setData.element.replace(patternForParent, parents[i]);

+        if (setData.ptcname != undefined) {

+            setData.ptcname = setData.ptcname.replace(patternForParentIndex, parentIndexes[i]);

+            setData.ptcname = setData.ptcname.replace(patternForParent, parents[i]);

+        }

+        if (setData.params != undefined) {

+            for (var j = 0; j < setData.params.length; ++j) {

+                setData.params[j].paramValue = setData.params[j].paramValue.replace(patternForParentIndex, parentIndexes[i]);

+                setData.params[j].paramValue = setData.params[j].paramValue.replace(patternForParent, parents[i]);

+            }

+        }

+    }

+}
\ No newline at end of file
diff --git a/htdocs/Utils/DsRestAPI/DsRestAPI.js b/htdocs/Utils/DsRestAPI/DsRestAPI.js
new file mode 100644
index 0000000..0811bb7
--- /dev/null
+++ b/htdocs/Utils/DsRestAPI/DsRestAPI.js
@@ -0,0 +1,84 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+/** DsRestAPI DataSource API calls */
+
+function DsRestAPI(extension) {
+    "use strict";
+    /** private member */
+    var mDsRestAPIComm;
+    var mThis = this;
+    /** constructor */
+    mDsRestAPIComm = new CDsRestAPIComm(extension);
+    /** public functions */
+    this.getData = function(aHandler, aSource, aElement, aParams, aPtcName) {
+        var lDSCall = [{getData : {
+                source : aSource,
+                element: aElement,
+                ptcname: aPtcName,
+                params : aParams
+            }}
+        ];
+        get(lDSCall, aHandler);
+    };
+
+    this.setData = function(aHandler, aSource, aElement, aContent, aType, aParams, aPtcName, aIndxs) {
+        var lDSCall = [{setData : {
+                source : aSource,
+                element: aElement,
+                ptcname: aPtcName,
+                params : aParams,
+                content: aContent,
+                indxsInList: aIndxs,
+                tp: aType
+            }}
+        ];
+        get(lDSCall, aHandler);
+    };
+
+    this.getList = function(aParam, aHandler) {
+        var lDSCall = {requests: aParam, "timeOut": 5.0};
+        mDsRestAPIComm.ajaxCall(lDSCall, function(data) {
+            aHandler(data);
+        });
+    };
+
+    this.getHelp = function(callback, aSource, aElement) {
+        function gotHelp(helpAns) {
+            var ok;
+            var data;
+            try {
+                ok = true;
+                data = JSON.parse(hex2a(helpAns.node.val));
+            } catch (e) {
+                ok = false;
+                data = "Error parsing Help data";
+            }
+            callback(ok, data);
+       }
+       if (aSource !== undefined && aElement !== undefined) {
+           this.getData(gotHelp, "DataSource", "help", [{"paramName": "Format", "paramValue": "JSON"}, {"paramName": "Source", "paramValue": aSource }, {"paramName": "Element", "paramValue": aElement}]);
+       } else if (aSource !== undefined) {
+           this.getData(gotHelp, "DataSource", "help", [{"paramName": "Format", "paramValue": "JSON"}, {"paramName": "Source", "paramValue": aSource }]);
+       } else {
+           this.getData(gotHelp, "DataSource", "help", [{"paramName": "Format", "paramValue": "JSON"}]);
+       }
+    };
+   
+    /** private functions */
+
+    function get(aParam, aHandler) {
+        function localHandler(aData) {
+            if (aHandler != undefined) {
+                if (aData && typeof aData[0] !== 'undefined') {
+                    aHandler(aData[0]);
+                } else {
+                    aHandler();
+                }
+            }
+        }
+        mThis.getList(aParam, localHandler);
+    }
+}
diff --git a/htdocs/Utils/DsRestAPI/DsRestAPIComm.js b/htdocs/Utils/DsRestAPI/DsRestAPIComm.js
new file mode 100644
index 0000000..b254d73
--- /dev/null
+++ b/htdocs/Utils/DsRestAPI/DsRestAPIComm.js
@@ -0,0 +1,77 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CDsRestAPIComm(p_extension) {

+    "use strict";

+    

+    var mRequestsDisabled = false;

+    var mTimeLastRequestFailed = 0;

+    var mNoAnswer = [{"node":{"val":"No answer", "tp":3}}];

+    

+    // disable cache (mainly for IE, it works all right with firefox and chrome)

+    $.ajaxSetup({cache: false});

+    

+    /* This gives a more sane initial value than being zero. */

+    var start = Date.now();

+    var ajaxCallURL = "api.dsapi";

+    if (p_extension != undefined) {

+        ajaxCallURL = "api." + p_extension;

+    }

+    

+    /** public functions */

+    this.ajaxCall = function(aData, aHandler) {

+        if (mRequestsDisabled) {

+            aData = {"requests": [], "timeOut": 5.0};

+        }

+        

+        var end = Date.now();

+        $('#cll_DsRestAPI_FPS').html((1000 / (end - start)).toFixed(2)); // diff to previous ajaxCall's end.

+        start = Date.now();

+        $.ajax({

+            url: ajaxCallURL,

+            type: 'POST',

+            data: JSON.stringify(aData),

+            //contentType: 'application/json',

+            //accepts: 'application/json',

+            dataType: 'text',

+            cache: false,

+            success: function(data, textStatus, jqXHR) {

+                var end = Date.now();

+                if (mRequestsDisabled) {

+                    mRequestsDisabled = false;

+                    // if we were disconnected for more than 15 secs, reload the page

+                    if (end - mTimeLastRequestFailed > 15000) {

+                        location.reload();

+                    } else {

+                        aHandler(mNoAnswer);

+                    }

+                } else {

+                    $('#cll_DsRestAPI_serverTime').html(parseFloat(jqXHR.getResponseHeader("X-EPTF-CLL-ServerTime")).toFixed(2));

+                    $('#cll_DsRestAPI_roundtrip').html(end - start);

+                    $('#cll_DsRestAPI_dataSize').html(data.length);

+                    $('#cll_DsRestAPI_error').html("");

+                    $('#cll_DsRestAPI_error').addClass("hidden");

+                    if (data && data !== "" && data !== " ")

+                        aHandler(JSON.parse(data).contentList);

+                    else

+                        aHandler(mNoAnswer);

+                }

+            },

+            error: function(jqXHR, textStatus, errorThrown) {

+                if (!mRequestsDisabled) {

+                    mRequestsDisabled = true;

+                    mTimeLastRequestFailed = Date.now();

+                }

+                

+                $('#cll_DsRestAPI_roundtrip').html(end - start);

+                $('#cll_DsRestAPI_error').html("State: UI has been disconnected<br/>Error: " + textStatus + "<br/>Action: reconnecting");

+                $('#cll_DsRestAPI_error').removeClass("hidden");

+                var end = Date.now();

+                aHandler(mNoAnswer);

+            },

+            timeout: 10000

+        });

+    };

+}

diff --git a/htdocs/Utils/DsRestAPI/RequestSchema.json b/htdocs/Utils/DsRestAPI/RequestSchema.json
new file mode 100644
index 0000000..7ab295c
--- /dev/null
+++ b/htdocs/Utils/DsRestAPI/RequestSchema.json
@@ -0,0 +1,252 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "definitions": {
+        "filter": {
+            "oneOf": [
+                {
+                    "title": "dataValue",
+                    "type": "object",
+                    "additionalProperties": false,
+                    "properties": {
+                        "dataValue": {
+                            "type": "string"
+                        }
+                    },
+                    "required": [
+                        "dataValue"
+                    ]
+                },
+                {
+                    "title": "filterRequest",
+                    "type": "object",
+                    "additionalProperties": false,
+                    "properties": {
+                        "request": {
+                            "type": "object",
+                            "additionalProperties": false,
+                            "properties": {
+                                "source": {
+                                    "type": "string"
+                                },
+                                "ptcname": {
+                                    "type": "string"
+                                },
+                                "element": {
+                                    "type": "string"
+                                },
+                                "params": {
+                                    "$ref": "#/definitions/filterParams"
+                                },
+                                "remapTo": {
+                                    "$ref": "#/definitions/filter"
+                                }
+                            },
+                            "required": [
+                                "source",
+                                "element"
+                            ]
+                        }
+                    }
+                }
+            ]
+        },
+        "filterParams": {
+            "type": "array",
+            "items": {
+                "title": "filterParam",
+                "type": "object",
+                "additionalProperties": false,
+                "properties": {
+                    "paramName": {
+                        "type": "string"
+                    },
+                    "paramValue": {
+                        "$ref": "#/definitions/filter"
+                    }
+                },
+                "required": [
+                    "paramName",
+                    "paramValue"
+                ]
+            }
+        },
+        "params": {
+            "type": "array",
+            "items": {
+                "title": "param",
+                "type" : "object",
+                "additionalProperties": false,
+                "properties": {
+                    "paramName": {
+                        "type": "string"
+                    },
+                    "paramValue": {
+                        "type": "string"
+                    }
+                },
+                "required": [
+                    "paramName",
+                    "paramValue"
+                ]
+            }
+        },
+        "getDataRequest": {
+            "title": "getDataRequest",
+            "type": "object",
+            "additionalProperties": false,
+            "properties": {
+                "getData": {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "properties": {
+                        "source": {
+                            "type": "string"
+                        },
+                        "ptcname": {
+                            "type": "string"
+                        },
+                        "element": {
+                            "type": "string"
+                        },
+                        "params": {
+                            "$ref": "#/definitions/params"
+                        },
+                        "cookie": {
+                            "type": "string"
+                        },
+                        "children": {
+                            "$ref": "#/definitions/requests"
+                        },
+                        "filter": {
+                            "$ref": "#/definitions/filter"
+                        },
+                        "rangeFilter": {
+                            "type": "object",
+                            "additionalProperties": false,
+                            "properties": {
+                                "offset": {
+                                    "type": "integer",
+                                    "minimum": 0
+                                },
+                                "count": {
+                                    "type": "integer",
+                                    "minimum": 0
+                                }
+                            }
+                        },
+                        "selection": {
+                            "type": "array",
+                            "items": {
+                                "title": "selection",
+                                "type": "integer"
+                            }
+                        },
+                        "selectionValues": {
+                            "type": "array",
+                            "items": {
+                                "title": "selectionValue",
+                                "type": "string"
+                            }
+                        },
+                        "writableInfo": {
+                            "type": "boolean"
+                        },
+                        "timeline": {
+                            "type": "object",
+                            "additionalProperties": false,
+                            "properties": {
+                                "period": {
+                                    "type": "number",
+                                    "minimum": 0
+                                },
+                                "maxpoints": {
+                                    "type": "integer",
+                                    "minimum": 0
+                                },
+                                "since": {
+                                    "type": "integer",
+                                    "minimum": 0
+                                }
+                            }
+                        }
+                    },
+                    "required": [
+                        "source",
+                        "element"
+                    ]
+                }
+            },
+            "required": [
+                "getData"
+            ]
+        },
+        "setDataRequest": {
+            "title": "setDataRequest",
+            "type": "object",
+            "additionalProperties": false,
+            "properties": {
+                "setData": {
+                    "type": "object",
+                    "properties": {
+                        "source": {
+                            "type": "string"
+                        },
+                        "ptcname": {
+                            "type": "string"
+                        },
+                        "element": {
+                            "type": "string"
+                        },
+                        "content": {
+                            "type": "string"
+                        },
+                        "tp": {
+                            "type": "integer"
+                        },
+                        "indxsInList": {
+                            "type": "array",
+                            "items": {
+                                "title": "index",
+                                "type": "integer"
+                            }
+                        },
+                        "params": {
+                            "$ref": "#/definitions/params"
+                        }
+                    },
+                    "required": [
+                        "source",
+                        "element",
+                        "content",
+                        "tp"
+                    ]
+                }
+            },
+            "required": [
+                "setData"
+            ]
+        },
+        "requests": {
+            "type": "array",
+            "items": {
+                "title": "request",
+                "oneOf": [
+                    {
+                        "$ref": "#/definitions/getDataRequest"
+                    },
+                    {
+                        "$ref": "#/definitions/setDataRequest"
+                    }
+                ]
+            }
+        }
+    },
+    "title": "DsRestAPI Request",
+    "type": "object",
+    "additionalProperties": true,
+    "properties": {
+        "requests": {
+            "$ref": "#/definitions/requests"
+        }
+    }
+}
\ No newline at end of file
diff --git a/htdocs/Utils/DsRestAPI/openapi.yaml b/htdocs/Utils/DsRestAPI/openapi.yaml
new file mode 100644
index 0000000..fc1a445
--- /dev/null
+++ b/htdocs/Utils/DsRestAPI/openapi.yaml
@@ -0,0 +1,216 @@
+openapi: 3.0.0

+servers:

+  - description: SwaggerHub API Auto Mocking

+    url: https://virtserver.swaggerhub.com/gre/DsRestAPI/1.0.0

+info:

+  description: DataSource Restful API

+  version: "1.0.0"

+  title: DataSource Restful API

+  contact:

+    email: tamas.levente.kiss@ericsson.com

+  license:

+    name: Eclipse Public License - v 1.0

+    url: 'http://www.eclipse.org/legal/epl-v10.html'

+tags:

+  - name: source

+    description: mandatory field

+  - name: element

+    description: mandatory field

+paths:

+  /api.extension:

+    post:

+      summary: posts a DsRestAPI request. The "extension" needs to be costumized by the application. Different applications may implement different extensions on the same server, serving different data elements.

+      operationId: postDsRestAPIRequest

+      description: posts a DsRestAPI request

+      responses:

+        '200':

+          description: request answered

+        '400':

+          description: bad request - invalid input object

+        '501':

+          description: unknown method - not implemented

+        '414':

+          description: Request-URI Too Long. Limit is 2000 octets

+      requestBody:

+        content:

+          application/json:

+            schema:

+              $ref: '#/components/schemas/DsAPIRequest'

+        description: JSON object to be issued

+components:

+  schemas:

+    DsAPIRequest:

+      type: object

+      required:

+        - requests

+      properties:

+        requests:

+          $ref: '#/components/schemas/requests'

+        timeout:

+          type: string

+          format: float

+          example: 5.0

+    requests:

+      type: array

+      example: [{"getData":{"source":"DataSource","element":"Sources"}}]

+      items:

+        title: request

+        oneOf:

+          - "$ref": "#/components/schemas/getDataRequest"

+          - "$ref": "#/components/schemas/setDataRequest"

+    getDataRequest:

+      title: getDataRequest

+      type: object

+      additionalProperties: false

+      properties:

+        getData:

+          type: object

+          additionalProperties: false

+          properties:

+            source:

+              type: string

+            ptcname:

+              type: string

+            element:

+              type: string

+            params:

+              "$ref": "#/components/schemas/params"

+            cookie:

+              type: string

+            children:

+              "$ref": "#/components/schemas/requests"

+            filter:

+              "$ref": "#/components/schemas/filter"

+            rangeFilter:

+              "$ref": "#/components/schemas/rangeFilter"

+            selection:

+              type: array

+              items:

+                title: selection

+                type: integer

+            selectionValues:

+              type: array

+              items:

+                title: selectionValue

+                type: string

+            writableInfo:

+              type: boolean

+            timeline:

+              type: object

+              additionalProperties: false

+              properties:

+                period:

+                  type: number

+                  minimum: 0

+                maxpoints:

+                  type: integer

+                  minimum: 0

+                since:

+                  type: integer

+                  minimum: 0

+          required:

+          - source

+          - element

+      required:

+      - getData

+    setDataRequest:

+      title: setDataRequest

+      type: object

+      additionalProperties: false

+      properties:

+        setData:

+          type: object

+          properties:

+            source:

+              type: string

+            ptcname:

+              type: string

+            element:

+              type: string

+            content:

+              type: string

+            tp:

+              type: integer

+            indxsInList:

+              type: array

+              items:

+                title: index

+                type: integer

+            params:

+              "$ref": "#/components/schemas/params"

+          required:

+          - source

+          - element

+          - content

+          - tp

+      required:

+      - setData

+    params:

+      type: array

+      items:

+        title: param

+        type: object

+        additionalProperties: false

+        properties:

+          paramName:

+            type: string

+          paramValue:

+            type: string

+        required:

+        - paramName

+        - paramValue

+    filter:

+      oneOf:

+      - title: dataValue

+        type: object

+        additionalProperties: false

+        properties:

+          dataValue:

+            type: string

+        required:

+        - dataValue

+      - title: filterRequest

+        type: object

+        additionalProperties: false

+        properties:

+          request:

+            type: object

+            additionalProperties: false

+            properties:

+              source:

+                type: string

+              ptcname:

+                type: string

+              element:

+                type: string

+              params:

+                "$ref": "#/components/schemas/filterParams"

+              remapTo:

+                "$ref": "#/components/schemas/filter"

+            required:

+            - source

+            - element

+    filterParams:

+      type: array

+      items:

+        title: filterParam

+        type: object

+        additionalProperties: false

+        properties:

+          paramName:

+            type: string

+          paramValue:

+            "$ref": "#/components/schemas/filter"

+        required:

+        - paramName

+        - paramValue

+    rangeFilter:

+      type: object

+      additionalProperties: false

+      properties:

+        offset:

+          type: integer

+          minimum: 0

+        count:

+          type: integer

+          minimum: 0
\ No newline at end of file
diff --git a/htdocs/Utils/FileHandler.js b/htdocs/Utils/FileHandler.js
new file mode 100644
index 0000000..8b3dcef
--- /dev/null
+++ b/htdocs/Utils/FileHandler.js
@@ -0,0 +1,134 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function FileHandler() {
+    "use strict";
+    
+    // disable cache (mainly for IE, it works all right with firefox and chrome)
+    $.ajaxSetup({cache: false});
+    
+    var v_cache = {};
+    var v_useCache = true;
+    
+    this.useCache = function(p_useCache) {
+        v_useCache = p_useCache;
+        v_cache = {};
+    };
+    
+    this.putFile = function(url, p_data, callback) {
+        $.ajax({
+            url: url,
+            type: 'PUT',
+            success: function(data) { callback(true, data); },
+            error: function(data) { callback(false, data); },
+            data: p_data,
+            dataType: 'text',
+            contentType: 'text',
+            timeout: 10000
+        });
+        
+        if (v_useCache) {
+            v_cache[url] = p_data;
+        }
+    };
+    
+    this.getDirectory = function(url, callback) {
+        $.ajax({
+            url: url,
+            type: 'LSDIR',
+            success: function(aData) {callback(JSON.parse(aData).fileList.sort());},
+            data: "",
+            dataType: 'text',
+            contentType: 'text',
+            timeout: 10000
+        });
+    };
+    
+    this.createDirectory = function(url, callback) {
+        $.ajax({
+            url: url,
+            type: 'MKDIR',
+            success: function(data) {callback(true, data);},
+            error: function(data) {callback(false, data);},
+            data: "",
+            dataType: "text",
+            timeout: 10000
+        });
+    };
+
+    this.delDirectory = function(url, callback) {
+        $.ajax({
+            url: url,
+            type: 'RMDIR',
+            success: function(data) { callback(true, data); },
+            error: function(data) { callback(false, data); },
+            data: "",
+            dataType: "text",
+            timeout: 10000
+        });
+    };
+    
+    
+
+    this.loadFile = function(url, callback) {
+        if (v_useCache && v_cache[url] != undefined) {
+            callback(true, v_cache[url]);
+            return;
+        }
+        
+        function success(data, textStatus, jqXHR) {
+            if (v_useCache) {
+                v_cache[url] = data;
+            }
+            callback(true, data);
+        }
+        
+        function error(data, textStatus, jqXHR) {
+            callback(false, "Loading: " + textStatus + " " + jqXHR);
+        }
+        
+        $.ajax({
+            url: url,
+            type: 'GET',
+            success: success,
+            error: error,
+            dataType: "text",
+            data: "",
+            timeout: 10000
+        });
+    };
+
+    this.importJsFile = function(file, p_callback) {
+        var v_callback = p_callback;
+        function success(data, textStatus, jqXHR) {
+            v_callback(true);
+        }
+        
+        function error(data, textStatus, jqXHR) {
+            v_callback(false, "Loading: " + textStatus + " " + jqXHR + " " + file);
+        }
+        
+        $.ajax({
+            url: file,
+            dataType: "script",
+            success: success,
+            error: error,
+            timeout: 10000
+        });
+    };
+    
+    this.loadCss = function(hmtlContentId, cssFile, callback) {
+        $("#" + hmtlContentId).load(cssFile, callback);
+    };
+    
+    this.loadCssFiles = function(cssFiles, id) {
+        for (var i = 0; i < cssFiles.length; ++i) {
+            // html ids should not contain / and . so we replace them with _
+            var cssId = cssFiles[i].replace(/[\/\.]/gi, "_");
+            $("#" + id).prepend('<style id="' + cssId + '" type="text/css"></style>');
+            this.loadCss(cssId, cssFiles[i]);
+        }
+    };
+}
\ No newline at end of file
diff --git a/htdocs/Utils/FileLoader.js b/htdocs/Utils/FileLoader.js
new file mode 100644
index 0000000..6ce1439
--- /dev/null
+++ b/htdocs/Utils/FileLoader.js
@@ -0,0 +1,66 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function FileLoader(p_url, p_fileHandler, p_data) {
+    "use strict";
+    var url = p_url;
+    var data = "";
+    if (p_data != undefined) {
+        data = p_data;
+    }
+    
+    var v_fileHandler = p_fileHandler;
+    
+    this.taskOperation = function(callback) {
+        function dataArrived(ok, p_data) {
+            if (ok) {
+                data = p_data;
+            }
+            callback(ok, data);
+        }
+        
+        v_fileHandler.loadFile(url, dataArrived);
+    };
+    
+    this.save = function(p_content, p_url, p_callback) {
+        if (p_content != undefined) {
+            data = p_content;
+        }
+        
+        var oldUrl = url;
+        if (p_url != undefined) {
+            oldUrl = url;
+            url = p_url;
+        }
+        
+        function callback(ok) {
+            if (!ok) {
+                url = oldUrl;
+            }
+            if (p_callback != undefined) {
+                p_callback(ok);
+            }
+        }
+        
+        if (url != undefined) {
+            v_fileHandler.putFile(url, data, callback);
+        } else {
+            callback(false);
+        }
+        
+    };
+    
+    this.getData = function() {
+        return data;
+    };
+    
+    this.setData = function(p_data) {
+        data = p_data;
+    };
+    
+    this.getUrl = function() {
+        return url;
+    };
+}
\ No newline at end of file
diff --git a/htdocs/Utils/HelpTreeBuilder.js b/htdocs/Utils/HelpTreeBuilder.js
new file mode 100644
index 0000000..ae64090
--- /dev/null
+++ b/htdocs/Utils/HelpTreeBuilder.js
@@ -0,0 +1,318 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function HelpTreeBuilder(p_flatHelp) {
+    "use strict";
+    
+    var v_flatHelp = p_flatHelp;
+    
+    this.getHelpTree = function(toSort) {
+        var help = {"sources": []};
+        
+        for (var i = 0; i < v_flatHelp.sources.length; ++i) {
+            var source = v_flatHelp.sources[i].source;
+            var dataElements = v_flatHelp.sources[i].dataElements;
+            
+            var tree = [];
+            help.sources.push({
+                "source": source,
+                "dataElements": tree
+            });
+            
+            collectRemaining(dataElements, tree, false);
+            if (toSort === true) {
+                sortChildren(tree);
+            }
+        }
+
+        return help;
+    };
+    
+    function sortChildren(dataElements) {
+        dataElements.sort(dataElementSort);
+        for (var i = 0; i < dataElements.length; ++i) {
+            traverseTree(dataElements[i], [dataElements[i]], function(path) {
+                var dataElement = path[path.length - 1];
+                if (dataElement.children != undefined && dataElement.children.length != 0) {
+                    dataElement.children.sort(dataElementSort);
+                }
+            });
+        }
+    }
+    
+    function dataElementSort(a, b) {
+        if (hasChildren(a)) {
+            if (hasChildren(b)) {
+                return dataElementNameCompare(a,b);
+            } else {
+                return -1;
+            }
+        } else if (hasChildren(b)) {
+            return 1;
+        } else {
+            return dataElementNameCompare(a,b);
+        }
+    }
+    
+    function hasChildren(dataElement) {
+        return dataElement.children != undefined && dataElement.children.length != 0
+    }
+    
+    function dataElementNameCompare(a, b) {
+        if (a.dataElement.name < b.dataElement.name) {
+            return -1;
+        } else if (a.dataElement.name > b.dataElement.name) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+    
+    function collectRemaining(dataElements, tree, force) {
+        var originalLength = dataElements.length;
+        
+        var inserted = true;
+        while (inserted) {
+            var i = 0;
+            inserted = false;
+            while (i < dataElements.length) {
+                if (insert(dataElements[i], tree, force)) {
+                    inserted = true;
+                    dataElements.splice(i, 1);
+                } else {
+                    ++i;
+                }
+            }
+        }
+        
+        // if we did not insert anything but should have
+        if (dataElements.length == originalLength && dataElements.length != 0) {
+            if (window["console"] != undefined && console.log != undefined) {
+                console.log("Failed to insert some elements into the help tree");
+                console.log(dataElements);
+            }
+            // insert the remaining to the root
+            for (var i = 0; i < dataElements.length; ++i) {
+                tree.push(dataElements[i]);
+            }
+        // if there are still some elements left, force insert them
+        } else if (dataElements.length != 0) {
+            // TODO: we could make this not recursive, but it is unlikely to cause problems
+            collectRemaining(dataElements, tree, true);
+        }
+    }
+    
+    function insert(dataElement, tree, force) {
+        var references = getReferencedTypes(dataElement);
+        if (references.length == 0) {
+            // we can insert it into the root
+            tree.push(dataElement);
+            return true;
+        } else {
+            return insertIntoBestMatch(dataElement, references, tree, force);
+        }
+    }
+    
+    function insertIntoBestMatch(dataElement, references, tree, force) {
+        // we give a score to every possible location and choose those that have a maximum score
+        var bestScore = 0;
+        var bestObjects = [];
+        var allReferencesFound = false;
+        
+        for (var i = 0; i < tree.length; ++i) {
+            traverseTree(tree[i], [tree[i]], function(path) {
+                var scoreObj = getScore(path, mcopy(references));
+                scoreObj["bestMatch"] = path[path.length - 1];
+                var score = scoreObj.score;
+                if (score > bestScore) {
+                    bestScore = score;
+                    bestObjects = [scoreObj];
+                    allReferencesFound = scoreObj.allReferencesFound
+                } else if (score == bestScore && allReferencesFound == scoreObj.allReferencesFound) {
+                    bestObjects.push(scoreObj);
+                }
+            });
+        }
+        
+        if (allReferencesFound) {
+            // we can insert the element, since we found all references
+            for (var i = 0; i < bestObjects.length; ++i) {
+                if (bestObjects[i].bestMatch.children != undefined) {
+                    bestObjects[i].bestMatch.children.push(dataElement);
+                } else {
+                    bestObjects[i].bestMatch.children = [dataElement];
+                }
+            }
+            return true;
+        } else if (force) {
+            // we must insert the missing references too, but it is possible that we cannot insert it this way either.
+            return insertMissingReferences(dataElement, bestObjects, tree);
+        } else {
+            // we could not insert the element
+            return false;
+        }
+    }
+    
+    function findAllReferences(references, tree) {
+        for (var i = 0; i < tree.length && references.length > 0; ++i) {
+            traverseTree(tree[i], [tree[i]], function(path) {
+                var type = getTypeName(path[path.length - 1]);
+                var index = references.indexOf(type);
+                if (index != -1) {
+                    references.splice(index, 1);
+                }
+            });
+        }
+        return references.length == 0;
+    }
+    
+    function traverseTree(dateElement, path, process) {
+        process(path);
+        if (dateElement.children != undefined) {
+            var tree = dateElement.children;
+            for (var i = 0; i < tree.length; ++i) {
+                path.push(tree[i]);
+                traverseTree(tree[i], path, process);
+                path.pop();
+            }
+        }
+    }
+    
+    function getScore(path, references) {
+        var ref = mcopy(references);
+        
+        var score = 0;
+        var types = [];
+        for (var i = 0; i < path.length; ++i) {
+            var type = getTypeName(path[i]);
+            var referencesIndex = references.indexOf(type);
+            if (types.indexOf(type) == -1) {
+                types.push(type);
+                if (referencesIndex != -1) {
+                    references.splice(referencesIndex, 1);
+                    // if we find a reference, increase the score by 1
+                    ++score;
+                }
+            }
+        }
+        
+        // the larger the depth, the larger the value we decrease the score with
+        score -= path.length / 20;
+        var allReferencesFound = references.length == 0;
+        if (allReferencesFound) {
+            // if we find all references the score will be large
+            score += 100;
+        }
+        
+        return {
+            "score": score,
+            "allReferencesFound": allReferencesFound,
+            "missingReferences": references,
+        };
+    }
+    
+    function insertMissingReferences(dataElement, bestMatches, tree) {
+        // the less elements we have to insert additionally, the higher the score
+        var maxScore = 0;
+        var maxObjects = [];
+        
+        for (var i = 0; i < bestMatches.length; ++i) {
+            var bestMatch = bestMatches[i].bestMatch;
+            var missingReferences = bestMatches[i].missingReferences;
+            
+            if (!findAllReferences(mcopy(missingReferences), tree)) {
+                // we could not find every reference in the whole tree, maybe later
+                continue;
+            }
+            
+            var bestScore = 0;
+            var bestPath;
+            var stillMissing;
+            
+            for (var i = 0; i < tree.length; ++i) {
+                traverseTree(tree[i], [tree[i]], function(path) {
+                    var scoreObj = getScore(path, mcopy(missingReferences));
+                    if (scoreObj.score > bestScore) {
+                        bestScore = scoreObj.score;
+                        bestPath = mcopy(path);
+                        stillMissing = scoreObj.missingReferences;
+                    }
+                });
+            }
+            
+            if (bestScore > maxScore) {
+                maxScore = bestScore;
+                maxObjects = [{
+                    "bestMatch": bestMatch,
+                    "bestPath": bestPath,
+                    "missingReferences": stillMissing
+                }];
+            } else if (bestScore == maxScore) {
+                maxObjects.push({
+                    "bestMatch": bestMatch,
+                    "bestPath": bestPath,
+                    "missingReferences": stillMissing
+                });
+            }
+        }
+        
+        if (maxObjects.length == 0) {
+            // we could not find any element in the tree that would allow us to insert the current element
+            return false;
+        }
+        
+        for (var i = 0; i < maxObjects.length; ++i) {
+            // we insert the whole path to the missing reference to be sure
+            var newBestMatch = insertPath(maxObjects[i].bestMatch, maxObjects[i].bestPath);
+            if (maxObjects[i].missingReferences.length != 0) {
+                insertMissingReferences(dataElement, [maxObjects[i]], tree);
+            } else {
+                if (newBestMatch.children != undefined) {
+                    newBestMatch.children.push(dataElement);
+                } else {
+                    newBestMatch.children = [dataElement];
+                }
+            }
+        }
+        
+        return true;
+    }
+    
+    function insertPath(insertInto, path) {
+        for (var i = 0; i < path.length; ++i) {
+            var obj = shallowcopy(path[i]);
+            obj.children = undefined;
+            if (insertInto.children != undefined) {
+                insertInto.children.push(obj);
+            } else {
+                insertInto.children = [obj];
+            }
+            insertInto = obj;
+        }
+        return insertInto;
+    }
+    
+    function getTypeName(p_dataElement) {
+        var dataElement = p_dataElement.dataElement;
+        if (dataElement.typeDescriptor != undefined && dataElement.typeDescriptor.typeName != undefined) {
+            return dataElement.typeDescriptor.typeName
+        } else {
+            return undefined;
+        }
+    }
+    
+    function getReferencedTypes(p_dataElement) {
+        var dataElement = p_dataElement.dataElement;
+        var references = [];
+        if (dataElement.parameters != undefined) {
+            for (var i = 0; i < dataElement.parameters.length; ++i) {
+                if (dataElement.parameters[i].typeDescriptor != undefined && dataElement.parameters[i].typeDescriptor.reference != undefined && dataElement.parameters[i].typeDescriptor.reference.typeName != undefined) {
+                    references.push(dataElement.parameters[i].typeDescriptor.reference.typeName);
+                }
+            }
+        }
+        return references;
+    }
+}
diff --git a/htdocs/Utils/JsTreeUtils.js b/htdocs/Utils/JsTreeUtils.js
new file mode 100644
index 0000000..e7c06c5
--- /dev/null
+++ b/htdocs/Utils/JsTreeUtils.js
@@ -0,0 +1,136 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function JsTreeUtils() {

+    "use strict";

+    

+    this.getPath = function(node) {

+        var path = [];

+        var strpath = "";

+        if (node.parents == undefined) {

+            return {"path": path, "strpath": strpath};

+        }

+        var level = node.parents.length;

+        var parent = $("#" + node.id);

+        path.unshift(parent.parent().children().index(parent[0]));

+        strpath = node.text;

+        for (var i = 0; i < level; ++i) {

+            parent = parent.parent().parent();

+            if (parent.children()[1] != undefined) {

+                path.unshift(parent.parent().children().index(parent[0]));

+                strpath = parent.children()[1].text + "." + strpath;

+            }

+        }

+        

+        return {"path": path, "strpath": strpath};

+    };

+    

+    function findOpenNodesInList(tree, nodes, open, path) {

+        for (var i = 0; i < nodes.length; ++i) {

+            path.push(i);

+            if (tree.jstree("is_open", nodes[i])) {

+                open.push(mcopy(path));

+                findOpenNodesInList(tree, tree.jstree("get_node", nodes[i]).children, open, path);

+            }

+            path.pop();

+        }

+    }

+    

+    this.findOpenNodes = function(tree) {

+        var id = "#";

+        var open = [];

+        var path = [];

+        var children = tree.jstree("get_node", "#").children;

+        if (children != undefined) {

+            findOpenNodesInList(tree, children, open, path);

+        }

+        return open;

+    };

+    

+    this.openNodes = function(tree, pathList) {

+        if (pathList != undefined) {

+            for (var i = 0; i < pathList.length; ++i) {

+                var path = mcopy(pathList[i]);

+                path.push(0);

+                this.expandPath(tree, path);

+            }

+        }

+    };

+    

+    this.getNodeIdFromPath = function(tree, path) {

+        var id = "#";

+        for (var i = 0; i < path.length; ++i) {

+            var children = tree.jstree("get_node", id).children;

+            if ((id !== "#" && tree.jstree("is_closed", id)) || children == undefined || children[path[i]] == undefined) {

+                return false;

+            }

+            id = children[path[i]];

+        }

+        return id;

+    };

+    

+    this.getLastNodeIdFromPath = function(tree, path) {

+        var id = "#";

+        for (var i = 0; i < path.length; ++i) {

+            var children = tree.jstree("get_node", id).children;

+            if ((id !== "#" && tree.jstree("is_closed", id)) || children == undefined || children[path[i]] == undefined) {

+                break;

+            }

+            id = children[path[i]];

+        }

+        return id;

+    };

+    

+    this.expandPath = function(tree, path) {

+        var id = "#";

+        for (var i = 0; i < path.length; ++i) {

+            if (id !== "#" && tree.jstree("is_closed", id)) {

+                tree.jstree("open_node", id);

+            }

+            var children = tree.jstree("get_node", id).children;

+            if ((id !== "#" && tree.jstree("is_closed", id)) || children == undefined || children[path[i]] == undefined) {

+                break;

+            }

+            id = children[path[i]];

+        }

+        return id;

+    };

+    

+    this.getPathOfSelection = function(tree) {

+        return this.getPath(tree.jstree("get_node", tree.jstree("get_selected"))).path;

+    };

+    

+    this.isNodeFromTree = function(node, tree) {

+        return tree.jstree("get_node", node.id);

+    };

+    

+    this.isNodeIdFromTree = function(id, tree) {

+        return tree.jstree("get_node", id);

+    };

+    

+    this.isRoot = function(node) {

+        return node.id === "#";

+    };

+    

+    this.getDepth = function(node, tree) {

+        return this.getPath(tree.jstree("get_node", node.id)).path.length;

+    };

+    

+    this.hasSameParentInTree = function(node1, node2, tree) {

+        var path1 = this.getPath(tree.jstree("get_node", node1.id)).path;

+        var path2 = this.getPath(tree.jstree("get_node", node2.id)).path;

+        return this.isNodeFromTree(node1, tree) && this.isNodeFromTree(node2, tree) && ((path1.length === 1 && path2.length === 1) || (path1[path1.length - 2] === path2[path2.length - 2]));

+    };

+    

+    this.isTheParentOfNode = function(node, parent, tree) {

+        // we could do something similar in the function above... does it work if the parent is "#"?

+        return $("#" + node.id).parent().parent()[0].id === parent.id;

+    };

+    

+    this.getIndexOfNode = function(node, tree) {

+        var path = this.getPath(tree.jstree("get_node", node.id)).path;

+        return path[path.length - 1];

+    };

+}
\ No newline at end of file
diff --git a/htdocs/Utils/JsonLoader.js b/htdocs/Utils/JsonLoader.js
new file mode 100644
index 0000000..8c4fcd4
--- /dev/null
+++ b/htdocs/Utils/JsonLoader.js
@@ -0,0 +1,69 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function JsonLoader(jsonFile, p_fileHandler, defaultValue) {

+    "use strict";

+    var url = jsonFile;

+    

+    var data = defaultValue;

+    var v_fileHandler = p_fileHandler;

+

+    this.taskOperation = function(callback) {

+        function dataArrived(ok, p_data) {

+            var error = false;

+            if (ok) {

+                try {

+                    data = JSON.parse(p_data);

+                } catch (e) {

+                    error = "Failed to parse JSON data: " + p_data;

+                }

+            } else {

+                error = "Failed to load " + url;

+            }

+            if (!error)

+                callback(true, data);

+            else

+                callback(false, error);

+        }

+        

+        v_fileHandler.loadFile(url, dataArrived);

+    };

+    

+    this.save = function(p_url, p_callback) {

+        var oldUrl = url;

+        if (p_url != undefined) {

+            oldUrl = url;

+            url = p_url;

+        }

+        

+        function callback(ok) {

+            if (!ok) {

+                url = oldUrl;

+            }

+            if (p_callback != undefined) {

+                p_callback(ok);

+            }

+        }

+        

+        if (url) {

+            v_fileHandler.putFile(url, JSON.stringify(data, null, 4), callback);

+        } else {

+            callback(false);

+        }

+        

+    };

+    

+    this.getData = function() {

+        return data;

+    };

+    

+    this.setData = function(p_data) {

+        data = p_data;

+    };

+    

+    this.getUrl = function() {

+        return url;

+    };

+}
\ No newline at end of file
diff --git a/htdocs/Utils/LineDrawer.js b/htdocs/Utils/LineDrawer.js
new file mode 100644
index 0000000..73401e5
--- /dev/null
+++ b/htdocs/Utils/LineDrawer.js
@@ -0,0 +1,312 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function LineDrawer(p_parentId, p_id, p_from, p_to, p_options) {

+    "use strict";

+    

+    var v_this = this;

+    

+    // params

+    var v_parentId = p_parentId;

+    var v_id = p_id;

+    var v_from = p_from;

+    var v_to = p_to;

+    var v_options =  {

+        "stroke" : "#456",

+        "strokeWidth" : 3,

+        "arrowForward" : true,

+        "markerStroke" : "#456",

+        "arrowHead" : "target",

+        "z-index" : 0

+    };

+    var zIndex = 0;

+    setOptions(p_options);

+

+    var v_svg;

+    

+    function setOptions(p_options) {

+        // copy given options to the default

+        for (var key in p_options) {

+            if (p_options.hasOwnProperty(key) && v_options.hasOwnProperty(key)) {

+                v_options[key] = p_options[key];

+            }

+        }

+        

+        // settings whose value depends on others

+        v_options.markerStroke = '-' + v_options.stroke.replace('#', '');

+    }

+    

+    this.init = function() {

+        createSVG();

+        createMarkers();

+        createPath();

+        v_this.update();

+    };

+    

+    function createSVG() {

+        v_svg = $("#" + v_parentId).createSVGNode({

+            "id": v_id,

+            "position": "absolute",

+            "style": "position: absolute; z-index: " + v_options["z-index"] + ";",

+            "pointer-events": "none",

+            "version": "1.1",

+            "z-index": v_options["z-index"]

+        });

+    }

+    

+    function setZIndex(svgElement) {

+        var amount;

+        if (v_from.getZIndex != undefined) {

+            amount = v_from.getZIndex();

+        }

+        if (v_to.getZIndex != undefined) {

+            var newAmount = v_to.getZIndex();

+            if (amount == undefined || newAmount > amount) {

+                amount = newAmount;

+            }

+        }

+        if (amount != undefined && amount != zIndex) {

+            svgElement.setAttribute("z-index", amount);

+            svgElement.style["z-index"] = amount;

+            zIndex = amount;

+        }

+    };

+    

+    function createMarkers() {

+        // the marker head descriptor

+        var markerHead = {

+            "id": v_id + "_head",

+            "orient": "auto",

+            "markerWidth": 4,

+            "markerHeight": 4,

+            "refX": 2,

+            "refY": 2

+        };

+        var markerFoot = shallowcopy(markerHead);

+        markerFoot.id = v_id + "_foot";

+

+        // we also need the marker path descriptor

+        var pathHead = {

+            "fill": v_options.stroke,

+            "stroke": v_options.stroke,

+            "stroke-linejoin": "miter",

+            "stroke-linecap": "round",

+            "d": "M0,0 V4 L2,2 Z"

+        };

+        var pathFoot = shallowcopy(pathHead);

+        pathFoot.d = "M4,0 V4 L2,2 Z";

+        

+        // finally we crete the defs element and fill it up

+        var defs = v_svg.createSVGNode("defs");

+        defs.createSVGNode("marker", markerHead)

+            .createSVGNode("path", pathHead);

+        defs.createSVGNode("marker", markerFoot)

+            .createSVGNode("path", pathFoot);

+    }

+    

+    function createPath() {

+        var svgattrs = {

+            "id": v_id + "_path",

+            "fill": "none",

+            "stroke": v_options.stroke,

+            "stroke-width": v_options.strokeWidth,

+            "stroke-linejoin": "round",

+            "stroke-linecap": "round",

+            "pointer-events": "none",

+            "shape-rendering": "geometricPrecision",

+            "stroke-antialiasing": "true"

+        };

+        

+        if(!isIE11 && !isIE10) {

+            // In IE10 and up, the url() virtual function crashes the SVG engine, hence nothing gets drawn in that <svg> element.

+            if (v_options.arrowHead === "target") {

+                svgattrs["marker-end"] = "url(#" + v_id + "_head)";

+            } else if (v_options.arrowHead === "source") {

+                svgattrs["marker-start"] = "url(#" + v_id + "_foot)";

+            } else if (v_options.arrowHead === "both") {

+                svgattrs["marker-end"] = "url(#" + v_id + "_head)";

+                svgattrs["marker-start"] = "url(#" + v_id + "_foot)";

+            }

+        }

+        

+        v_svg.createSVGNode("path", svgattrs);

+    }

+    

+    this.remove = function() {

+        $("#" + v_id).remove();

+    };

+    

+    function findMinOffsetFromList(list, element) {

+        var minAmount = Math.abs(list[0].top - element.top) + Math.abs(list[0].left - element.left);

+        var min = 0;

+        for (var i = 1; i < list.length; ++i) {

+            var amount = Math.abs(list[1].top - element.top) + Math.abs(list[1].left - element.left);

+            if (amount < minAmount) {

+                minAmount = amount;

+                min = i;

+            }

+        }

+        return [min, minAmount];

+    }

+    

+    function getFinalCoordinates(sourceOffset, targetOffset) {

+        var x1 = Math.round(sourceOffset.top);

+        var y1 = Math.round(sourceOffset.left);

+        

+        var x2 = Math.round(targetOffset.top);

+        if (x2 === x1) {

+            x2++;

+        }

+        var y2 = Math.round(targetOffset.left);

+        if (y2 === y1) {

+            y2++;

+        }

+        return [x1, y1, x2, y2];

+    }

+    

+    function getOffsetCoordinates() {

+        if (!v_from.multiple && !v_to.multiple) {

+            // only one source and one target

+            return getFinalCoordinates(v_from.getOffset(), v_to.getOffset());

+        } else if (v_from.multiple && !v_to.multiple) {

+            // multiple sources and one target

+            var list = v_from.getOffsets();

+            var element = v_to.getOffset();

+            var min = findMinOffsetFromList(list, element);

+            return getFinalCoordinates(list[min[0]], element);

+        } else if (!v_from.multiple && v_to.multiple) {

+            // one surce and multiple targets

+            var list = v_to.getOffsets();

+            var element = v_from.getOffset();

+            var min = findMinOffsetFromList(list, element);

+            return getFinalCoordinates(element, list[min[0]]);

+        } else {

+            // multiple source and multiple targets

+            var sourceList = v_from.getOffsets();

+            var targetList = v_to.getOffsets();

+            // assume the first is the minimum

+            var minsource = 0;

+            var min = findMinOffsetFromList(targetList, sourceList[0]);

+            // we need the index of the target whose distance from the current source element is minimal

+            var mintarget = min[0];

+            // and the distance itself

+            var minAmount = min[1];

+            // find the real minimum from the rest

+            for (var i = 1; i < sourceList.length; ++i) {

+                var element = sourceList[i];

+                min = findMinOffsetFromList(targetList, element);

+                if (min[1] < minAmount) {

+                    minsource = i;

+                    mintarget = min[0];

+                    minAmount = min[1];

+                }

+            }

+            return getFinalCoordinates(sourceList[minsource], targetList[mintarget]);

+        }

+    }

+    

+    function getStyle(fromX, fromY, toX, toY) {

+        var d = 'M' + fromX + ',' + fromY + ' C';

+        

+        if (v_from.style == "vertical") {

+            d += fromX + ',' + ( (fromY + toY) / 2 ) + ' ';

+        } else {

+            d += ( (fromX + toX) / 2 ) + ',' + fromY + ' ';

+        }

+        

+        if (v_to.style == "vertical") {

+            d += toX + ',' + ( (fromY + toY) / 2 );

+        } else {

+            d += ( (fromX + toX) / 2 ) + ',' + toY;

+        }

+        

+        d += ' ' + toX + ',' + toY;

+        return d;

+    }

+    

+    this.update = function() {

+        if ((v_from.isEnabled != undefined && !v_from.isEnabled()) || (v_to.isEnabled != undefined && !v_to.isEnabled())) {

+            // check whether one of the endpoints is disabled

+            $("#" + v_id).css("display", "none");

+            return;

+        } else {

+            $("#" + v_id).css("display", "block");

+        }

+        

+        var offsets = getOffsetCoordinates();

+        var x1 = offsets[0];

+        var y1 = offsets[1];

+        var x2 = offsets[2];

+        var y2 = offsets[3];

+        

+        // these are the only values we need, and we need them all

+        // the bounding box position

+        var boundingBoxOffset = {"top" : 0, "left" : 0};

+        var boundingBoxWidth = 0;

+        var boundingBoxHeight = 0;

+        

+        // the corners of the bounding box we should connect

+        var fromX = 0;

+        var fromY = 0;

+        var toX = 0;

+        var toY = 0;

+        

+        if (x2 > x1 && y2 > y1) {

+            boundingBoxOffset.top = x1 - 5;

+            boundingBoxOffset.left = y1 - 5;

+            boundingBoxWidth = y2 - y1 + 10;

+            boundingBoxHeight = x2 - x1 + 10;

+            fromX = 0 + 5;

+            fromY = 0 + 5;

+            toX = boundingBoxWidth - 5;

+            toY = boundingBoxHeight - 5;

+        } else if (x2 > x1 && y2 < y1) {

+            boundingBoxOffset.top = x1 - 5;

+            boundingBoxOffset.left = y2 - 5;

+            boundingBoxWidth = y1 - y2 + 10;

+            boundingBoxHeight = x2 - x1 + 10;

+            fromX = boundingBoxWidth - 5;

+            fromY = 0 + 5;

+            toX = 0 + 5;

+            toY = boundingBoxHeight - 5;

+        } else if (x2 < x1 && y2 > y1) {

+            boundingBoxOffset.top = x2 - 5;

+            boundingBoxOffset.left = y1 - 5;

+            boundingBoxWidth = y2 - y1 + 10;

+            boundingBoxHeight = x1 - x2 + 10;

+            fromX = 0 + 5;

+            fromY = boundingBoxHeight - 5;

+            toX = boundingBoxWidth - 5;

+            toY = 0 + 5;

+        } else if (x2 < x1 && y2 < y1) {

+            boundingBoxOffset.top = x2 - 5;

+            boundingBoxOffset.left = y2 - 5;

+            boundingBoxWidth = y1 - y2 + 10;

+            boundingBoxHeight = x1 - x2 + 10;

+            fromX = boundingBoxWidth - 5;

+            fromY = boundingBoxHeight - 5;

+            toX = 0 + 5;

+            toY = 0 + 5;

+        }

+

+        v_svg.offset(boundingBoxOffset);

+        // in IE and chrome we need to set the offset twice so it gets calculated correctly

+        v_svg.offset(boundingBoxOffset);

+        var svgElement = document.getElementById(v_id);

+        svgElement.setAttribute("height", boundingBoxHeight);

+        svgElement.setAttribute("width", boundingBoxWidth);

+        svgElement.style.height = boundingBoxHeight;

+        svgElement.style.width = boundingBoxWidth;

+        

+        //var d = 'M' + fromX + ',' + fromY + ' C' + ( (fromX + toX) / 2 ) + ',' + fromY + ' ' + ( (fromX + toX) / 2 ) + ',' + toY + ' ' + toX + ',' + toY;

+        

+        var d = getStyle(fromX, fromY, toX, toY);

+        document.getElementById(v_id + "_path").setAttribute("d", d);

+        

+        setZIndex(svgElement);

+    };

+}

+

+//# sourceURL=Utils\LineDrawer.js

diff --git a/htdocs/Utils/Polyfill.js b/htdocs/Utils/Polyfill.js
new file mode 100644
index 0000000..9bc8d4e
--- /dev/null
+++ b/htdocs/Utils/Polyfill.js
@@ -0,0 +1,167 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+/*

+ * ## What is polyfill?

+ * - https://remysharp.com/2010/10/08/what-is-a-polyfill

+ * - https://en.wikipedia.org/wiki/Polyfill

+ *

+ * Polyfill is a kind of regressive enhancement, a backport of native APIs in managed code.

+ */

+// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

+if (!Object.keys) {

+    Object.keys = (function() {

+        'use strict';

+        var hasOwnProperty = Object.prototype.hasOwnProperty,

+            hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),

+            dontEnums = [

+                'toString',

+                'toLocaleString',

+                'valueOf',

+                'hasOwnProperty',

+                'isPrototypeOf',

+                'propertyIsEnumerable',

+                'constructor'

+            ],

+            dontEnumsLength = dontEnums.length;

+

+        return function(obj) {

+            if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {

+                throw new TypeError('Object.keys called on non-object');

+            }

+

+            var result = [], prop, i;

+

+            for (prop in obj) {

+                if (hasOwnProperty.call(obj, prop)) {

+                    result.push(prop);

+                }

+            }

+

+            if (hasDontEnumBug) {

+                for (i = 0; i < dontEnumsLength; i++) {

+                    if (hasOwnProperty.call(obj, dontEnums[i])) {

+                        result.push(dontEnums[i]);

+                    }

+                }

+            }

+            return result;

+        };

+    }());

+}

+

+/*

+ * From https://github.com/itsa/polyfill/blob/master/old-lib/object.defineproperty.js

+ */

+if (!Object.defineProperty) {

+    Object.defineProperty =  function(object, property, descriptor) {

+        'use strict';

+        object[property] = descriptor.value;

+    };

+}

+

+/*

+ * From https://github.com/itsa/polyfill/blob/master/old-lib/object.defineproperty.js

+ */

+if (!Object.defineProperties) {

+    Object.defineProperties = function(object, descriptors) {

+        'use strict';

+        var property;

+        for (property in descriptors) {

+            Object.defineProperty(object, property, descriptors[property]);

+        }

+        return object;

+    };

+}

+

+if (!Date.now) { //  ECMA-262 5th edition, not in IE9-

+    Date.now = function now() {

+        "use strict";

+        return new Date().getTime();

+    };

+}

+

+if (!String.prototype.includes) { // ECMAScript 6 only.

+  String.prototype.includes = function() {'use strict';

+    return String.prototype.indexOf.apply(this, arguments) !== -1;

+  };

+}

+

+if (!String.prototype.startsWith) { // ECMAScript 6 only.

+  String.prototype.startsWith = function(searchString, position) {'use strict';

+    position = position || 0;

+    return this.indexOf(searchString, position) === position;

+  };

+}

+

+if (!String.prototype.endsWith) { // ECMAScript 6 only.

+  String.prototype.endsWith = function(searchString, position) {'use strict';

+      var subjectString = this.toString();

+      if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) {

+        position = subjectString.length;

+      }

+      position -= searchString.length;

+      var lastIndex = subjectString.indexOf(searchString, position);

+      return lastIndex !== -1 && lastIndex === position;

+  };

+}

+

+// Production steps of ECMA-262, Edition 5, 15.4.4.21

+// Reference: http://es5.github.io/#x15.4.4.21

+if (!Array.prototype.reduce) { // IE9+

+  Array.prototype.reduce = function(callback, initialValue) {

+    'use strict';

+    if (this == null) {

+      throw new TypeError('Array.prototype.reduce called on null or undefined');

+    }

+    if (typeof callback !== 'function') {

+      throw new TypeError(callback + ' is not a function');

+    }

+    var t = Object(this), len = t.length >>> 0, k = 0, value;

+    if (arguments.length === 2) {

+      value = initialValue;

+    } else {

+      while (k < len && !(k in t)) {

+        k++;

+      }

+      if (k >= len) {

+        throw new TypeError('Reduce of empty array with no initial value');

+      }

+      value = t[k++];

+    }

+    for (; k < len; k++) {

+      if (k in t) {

+        value = callback(value, t[k], k, t);

+      }

+    }

+    return value;

+  };

+}

+

+window.performance = (window.performance || {

+    offset: Date.now(), // Timestamp of init.

+    now: function now(){ // ms elapsed since offset.

+        return Date.now() - this.offset;

+    }

+});

+

+(function (global) { // console NOOP for oldff

+    "use strict";

+    var CONSOLE = {

+        log: function() { /* NOOP */ },

+        info: function() { /* NOOP */ },

+        warn: function() { /* NOOP */ },

+        error: function() { /* NOOP */ }

+    };

+    global.console || (function(GlobalPrototype) {

+        GlobalPrototype.console = CONSOLE;

+    }(global.prototype));

+}(typeof global !== 'undefined' ? global : this));

+

+Number.isInteger = Number.isInteger || function(value) {

+    return typeof value === "number" && isFinite(value) && Math.floor(value) === value;

+};

+

+//# sourceURL=Utils\Polyfill.js

diff --git a/htdocs/Utils/RequestBuilderFromHelp_full.js b/htdocs/Utils/RequestBuilderFromHelp_full.js
new file mode 100644
index 0000000..8bf1ab6
--- /dev/null
+++ b/htdocs/Utils/RequestBuilderFromHelp_full.js
@@ -0,0 +1,255 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function DSHelpToRequest_full(aHelp)
+{
+    //mlog("aHelp: ", aHelp);
+    //mlog("aHelp JSON: ",JSON.stringify(aHelp, null, 2));
+    //mlog("Requests.ExecCtrl: ", Requests.ExecCtrl);
+    var aParentIndexes = [];
+    //for (var i =3; i < 4; i++) // currently only ExecCtrl
+    var lHelp=JSON.parse(JSON.stringify(aHelp));
+    if (lHelp.sources)
+    {
+        for (var i = 0; i < lHelp.sources.length; i++)
+        {
+            PreprocessHelpList(lHelp.sources[i].dataElements, lHelp.sources[i].source, lHelp.sources[i].dataElements, aParentIndexes);
+        }
+    }
+    var lReq = [];
+    aParentIndexes = [];
+    if (lHelp.sources)
+    {
+        for (var i = 0; i < lHelp.sources.length; i++)
+        {
+            HelpListToRequestList(lReq, lHelp.sources[i].dataElements, lHelp.sources[i].source, lHelp.sources[i].dataElements, aParentIndexes);
+        }
+    }
+    //mlog("lReq: ", lReq);
+    //mlog("lReq JSON: ",JSON.stringify(lReq, null, 2));
+    return lReq;
+    //return JSON.stringify(lReq, null, 2);
+}
+
+//                          children                 root          index of child at current level
+function PreprocessHelpList(aHelpList, aSourceName, aHelpListTop, aParentIndexes)
+{
+    var tempParentIndexes = JSON.stringify(aParentIndexes, null, 2); // TODO replace it
+    for (var i = 0; i < aHelpList.length; i++)
+    {
+        aParentIndexes = JSON.parse(tempParentIndexes);
+        if (aHelpList[i].children != undefined)
+        {
+            aParentIndexes[aParentIndexes.length] = i;
+            PreprocessHelpList(aHelpList[i].children, aSourceName, aHelpListTop, aParentIndexes);
+        }
+
+        CalcParamsOrInsertParents(aHelpList[i].dataElement, aHelpListTop, aParentIndexes, i,false);
+    }
+}
+
+function HelpListToRequestList(aOutReq, aHelpList, aSourceName, aHelpListTop, aParentIndexes)
+{
+    var tempParentIndexes = JSON.stringify(aParentIndexes, null, 2); // TODO replace it
+    for (var i = 0; i < aHelpList.length; i++)
+    {
+        aParentIndexes = JSON.parse(tempParentIndexes);
+        var idx = aOutReq.length;
+        var lReq = [];
+        if (aHelpList[i].children != undefined)
+        {
+            aParentIndexes[aParentIndexes.length] = i;
+            HelpListToRequestList(lReq, aHelpList[i].children, aSourceName, aHelpListTop, aParentIndexes);
+        }
+
+        aOutReq[idx] = {};
+        aOutReq[idx].getData = {
+            source: aSourceName,
+            element: aHelpList[i].dataElement.name,
+            selection: null,
+            params: CalcParamsOrInsertParents(aHelpList[i].dataElement, aHelpListTop, aParentIndexes, i, true),
+            children: lReq
+        };
+    }
+}
+
+function CalcParamsOrInsertParents(aDataElement, aHelpListTop, aParentIndexes, aCurrentIndex, aCalcParams)
+{
+    //mlog("*** CalcParamsOrInsertParents processing: ", aDataElement);
+    var lParameters = [];
+    var lParams = [];
+
+    if (aDataElement.parameters != undefined)
+    {
+        lParameters = aDataElement.parameters;
+        for (var i = 0; i < lParameters.length; i++)
+        {
+            //mlog("processing parameter #",JSON.parse(JSON.stringify(i)),": ", JSON.parse(JSON.stringify(lParameters[i].name)));
+            lParams[i]= {};
+            lParams[i].paramName = lParameters[i].name;
+
+            if (lParameters[i].typeDescriptor.reference != undefined)
+            {
+                var lLevel=0;
+                //if (aCalcParams == true)
+                //    mlog("\\\\\\\\\\searching for", lParameters[i].typeDescriptor.reference.typeName);
+                var lNestingLevel = GetReferenceNestingLevel(lParameters[i].typeDescriptor.reference.typeName, aHelpListTop, lLevel, aParentIndexes);
+                if (aCalcParams === false)
+                {
+                    if (lNestingLevel === -1)
+                    {
+                        //mlog("ELEMENT NOT FOUND IN PARENT TREE: ",lParameters[i].typeDescriptor.reference.typeName);
+                        lLevel = 0;
+                        var lParentIndexes = [];
+                        //mlog("\\\\\\\\\\searching globally for", lParameters[i].typeDescriptor.reference.typeName);
+                        //mlog("******searching in: ", aHelpListTop);
+                        lNestingLevel = GetReferenceNestingLevelFromFullBranch(lParameters[i].typeDescriptor.reference.typeName, aHelpListTop, lLevel, lParentIndexes);
+                        //mlog("*****lParentIndexes calculated:", lParentIndexes, " nesting level: ", lNestingLevel);
+                        if (lNestingLevel === -1)
+                        {
+                            mlog("!!!!THIS SHOULD NEVER HAPPEN2!!!!  dataelement: ", aDataElement);
+                        }
+                        else
+                        {
+                            InsertParents(aCurrentIndex,aParentIndexes,lParentIndexes,aHelpListTop);
+                        }
+                    }
+                }
+                else
+                {
+                    if (lNestingLevel === -1)
+                    {
+                        mlog("!!!!THIS SHOULD NEVER HAPPEN!!!!  dataelement: ", aDataElement);
+                    }
+                    lParams[i].paramValue= "%Parent"+lNestingLevel+"%";
+                    //mlog("paramValue of ", lParams[i].paramName, ": ",lParams[i].paramValue)
+                }
+            }
+            if (lParameters[i].typeDescriptor.valueType != undefined && aCalcParams === true)
+            {
+                lParams[i].paramValue= lParameters[i].exampleValue;
+            }
+        }
+    }
+    return lParams;
+}
+
+function GetCurrentElement(aCurrentIndex, aParentIndexesCurrent, aHelpCurrent, aLevel)
+{
+    if (aParentIndexesCurrent.length === aLevel)
+    {
+        return aHelpCurrent[aCurrentIndex];
+    }
+    ++aLevel;
+    return GetCurrentElement(aCurrentIndex, aParentIndexesCurrent, aHelpCurrent[aParentIndexesCurrent[aLevel-1]].children, aLevel);
+}
+
+function SetCurrentElement(aCurrentIndex, aParentIndexesCurrent, aHelpCurrent, aLevel, aElementToSet)
+{
+    if (aParentIndexesCurrent.length === aLevel)
+    {
+        aHelpCurrent[aCurrentIndex] = aElementToSet;
+    }
+    else
+    {
+        ++aLevel;
+        SetCurrentElement(aCurrentIndex, aParentIndexesCurrent, aHelpCurrent[aParentIndexesCurrent[aLevel-1]].children, aLevel, aElementToSet);
+    }
+}
+
+function InsertParents(aCurrentIndex, aParentIndexesCurrent, aParentIndexesSource, aHelpListTop)
+{
+    //mlog("*********InsertParents*************");
+    //mlog("aCurrentIndex: ", aCurrentIndex)
+    //mlog("aParentIndexesCurrent: ", aParentIndexesCurrent)
+    //mlog("aParentIndexesSource: ", aParentIndexesSource)
+    //mlog("aHelpListTop: ", JSON.parse(JSON.stringify(aHelpListTop,null,2)));
+
+    var lLevel = 0;
+    var lCurrentElement = GetCurrentElement(aCurrentIndex, aParentIndexesCurrent, aHelpListTop, lLevel);
+    //mlog("current element: ", lCurrentElement);
+
+
+    var lSourceBranch = [];
+    lLevel = 0;
+    GetSourceBranch(aParentIndexesSource, aHelpListTop, lSourceBranch, lLevel, lCurrentElement);
+    //mlog("sourceBranch: ", lSourceBranch);
+    //lCurrentElement = lSourceBranch[0];
+    lLevel = 0;
+    SetCurrentElement(aCurrentIndex, aParentIndexesCurrent, aHelpListTop, lLevel, lSourceBranch[0]);
+    //mlog("aHelpListTopAfter: ", JSON.parse(JSON.stringify(aHelpListTop)));
+
+}
+
+function GetSourceBranch(aParentIndexesSource, aHelpListTop, aSourceBranch, aLevel, aCurrentElement)
+{
+    if (aParentIndexesSource.length === aLevel)
+    {
+        aSourceBranch[0] = aCurrentElement;
+    }
+    else
+    {
+        aSourceBranch[0] = JSON.parse(JSON.stringify(aHelpListTop[aParentIndexesSource[aLevel]]));
+        aSourceBranch[0].children = [];
+        ++aLevel;
+        GetSourceBranch(aParentIndexesSource, aHelpListTop[aParentIndexesSource[aLevel-1]].children, aSourceBranch[0].children, aLevel, aCurrentElement);
+    }
+}
+
+function GetReferenceNestingLevel(aTypeName, aCurrentBranch, aLevel, aParentIndexes)
+{
+    //mlog("\\\\\\\\\\\\ searchin' in: ", aCurrentBranch, aParentIndexes);
+    var lRetVal=-1;
+    var i = aParentIndexes[aLevel];
+
+    if (aCurrentBranch[i] != undefined)
+    {
+        //mlog("---------aCurrentBranch[i].dataElement.typeDescriptor.typeName / aTypeName", aCurrentBranch[i].dataElement.typeDescriptor.typeName, "/", aTypeName, aLevel);
+        if (aCurrentBranch[i].dataElement.typeDescriptor != undefined && aCurrentBranch[i].dataElement.typeDescriptor.typeName === aTypeName)
+        {
+            lRetVal = aLevel;
+        }
+        else if (aCurrentBranch[i].children != undefined)
+        {
+            lRetVal = GetReferenceNestingLevel(aTypeName, aCurrentBranch[i].children, aLevel+1, aParentIndexes);
+        }
+    }
+    //mlog("///////////returning: ", lRetVal);
+    return lRetVal;
+}
+
+function GetReferenceNestingLevelFromFullBranch(aTypeName, aCurrentBranch, aLevel, aParentIndexes)
+{
+    //mlog("**********************GetReferenceNestingLevelFromFullBranch*******************")
+    //mlog("aCurrentBranch: ",aCurrentBranch);
+    var lRetVal = -1;
+    for (var i = 0; i < aCurrentBranch.length; i++)
+    {
+        aParentIndexes[aLevel] = i;
+        if (aCurrentBranch[i] != undefined)
+        {
+            //mlog("currentBranch[", i,"]=",aCurrentBranch[i]);
+            //mlog("-------typeName: ",aCurrentBranch[i].dataElement.typeDescriptor.typeName, ":", aTypeName);
+            if (aCurrentBranch[i].dataElement.typeDescriptor != undefined && aCurrentBranch[i].dataElement.typeDescriptor.typeName === aTypeName)
+            {
+                lRetVal = aLevel;
+                return lRetVal;
+            }
+            if (aCurrentBranch[i].children != undefined)
+            {
+                ++aLevel;
+                lRetVal = GetReferenceNestingLevelFromFullBranch(aTypeName, aCurrentBranch[i].children, aLevel, aParentIndexes);
+                if (lRetVal !== -1)
+                {
+                    return lRetVal;
+                } else {
+                  --aLevel;
+                  aParentIndexes.pop();
+                }
+            }
+        }
+    }
+    return lRetVal;
+}
diff --git a/htdocs/Utils/RequestBuilderFromHelp_manual.js b/htdocs/Utils/RequestBuilderFromHelp_manual.js
new file mode 100644
index 0000000..70af30d
--- /dev/null
+++ b/htdocs/Utils/RequestBuilderFromHelp_manual.js
@@ -0,0 +1,691 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function DSHelpToRequest_manual() {

+    "use strict";

+    var PATTERN = /%Parent(\d+)%/g;

+    var PATTERN_IDX = /%Parent(\d+)::idx%/g;

+

+    var v_help;

+    var v_fullRequest;

+    var v_this = this;

+

+    this.setHelp = function(p_help) {

+        v_help = p_help;

+    };

+

+    this.setRequest = function(p_request) {

+        v_fullRequest = p_request;

+    };

+

+    ///////////////////// UTILITIES, ADDING AND CREATING REQUESTS //////////////////////////////

+

+    this.createEmptyRequest = function(p_pos) {

+        var request = {

+            "getData" : {

+                "source" : "Source",

+                "element" : "Element"

+            }

+        };

+        requestCreated(request, p_pos);

+        return request;

+    };

+

+    this.createRequest = function(p_helpPath, p_pos) {

+        var request = generateGetData(p_helpPath, []);

+        requestCreated(request, p_pos);

+        return request;

+    };

+

+    function requestCreated(p_request, p_pos) {

+        if (p_pos == undefined) {

+            p_pos = v_fullRequest.length;

+        }

+

+        v_fullRequest.splice(p_pos, 0, p_request);

+    }

+

+    this.addEmptyChildRequest = function(p_requestPath, p_pos) {

+        var childRequest = {

+            "getData" : {

+                "source" : "Source",

+                "element" : "Element"

+            }

+        };

+        childRequestCreated(childRequest, p_requestPath, p_pos);

+        return childRequest;

+    };

+

+    this.addChildRequest = function(p_helpPath, p_requestPath, p_pos, p_setData) {

+        if (!doesNotHaveGetDataOnPath(p_requestPath)) {

+            var childRequest = generateGetData(p_helpPath, p_requestPath);

+

+            if (p_setData) {

+                childRequest.setData = childRequest.getData;

+                childRequest.getData = undefined;

+                addContentAndTpToSetData(childRequest.setData, getHelpDataElement(p_helpPath).dataElement.dataElement);

+            }

+

+            childRequestCreated(childRequest, p_requestPath, p_pos);

+            return childRequest;

+        }

+    };

+

+    function addContentAndTpToSetData(setData, helpElement) {

+        if (helpElement.valueType == "intType") {

+            setData.content = "0";

+            setData.tp = 1;

+        } else if (helpElement.valueType == "floatType") {

+            setData.content = "0.0";

+            setData.tp = 2;

+        } else if (helpElement.valueType == "boolType") {

+            setData.content = "true";

+            setData.tp = 3;

+        } else if (helpElement.valueType == "charstringType") {

+            setData.content = "";

+            setData.tp = 4;

+        } else if (helpElement.valueType == "octetstringType") {

+            setData.content = "";

+            setData.tp = 5;

+        } else if (helpElement.valueType == "hexstringType") {

+            setData.content = "";

+            setData.tp = 6;

+        } else if (helpElement.valueType == "bitstringType") {

+            setData.content = "";

+            setData.tp = 7;

+        } else if (helpElement.valueType == "integerlistType") {

+            setData.content = "0";

+            setData.tp = 8;

+            setData.indxsInList = [0];

+        } else if (helpElement.valueType == "floatlistType") {

+            setData.content = "0.0";

+            setData.tp = 9;

+            setData.indxsInList = [0];

+        } else if (helpElement.valueType == "charstringlistType") {

+            setData.content = "";

+            setData.tp = 10;

+            setData.indxsInList = [0];

+        } else if (helpElement.valueType == "statusLEDType") {

+            setData.content = "[led:green]Ok";

+            setData.tp = 11;

+        } else {

+            setData.content = "";

+            setData.tp = 0;

+        }

+    }

+

+    this.copyRequest = function(p_path) {

+        var currentRq = v_this.getRequestFromPath(p_path);

+        var setOrGetData = getOrSetData(currentRq);

+        var requestToCopy = {};

+        requestToCopy[setOrGetData] = mcopy(v_this.getRequestCopy(p_path));

+        var position = p_path.pop();

+        ++position;

+        if (p_path.length != 0) {

+            var parent = v_this.getRequestFromPath(p_path);

+            parent = parent[getOrSetData(parent)];

+            parent.children.splice(position, 0, requestToCopy);

+        } else {

+            v_fullRequest.splice(position, 0, requestToCopy);

+        }

+        return requestToCopy;

+    };

+

+    this.getRequestCopy = function(p_path) {

+        var original = v_this.getRequestFromPath(p_path);

+        original = original[getOrSetData(original)];

+        var copy = mcopy(original);

+        delete copy.children;

+        return copy;

+    };

+

+    function childRequestCreated(p_childRequest, p_requestPath, p_pos) {

+        var request = v_this.getRequestFromPath(p_requestPath);

+        request = request[getOrSetData(request)];

+        if (request.children == undefined) {

+            request.children = [];

+        }

+

+        if (p_pos == undefined) {

+            p_pos = request.children.length;

+        }

+

+        if (request.ptcname != undefined) {

+            p_childRequest.ptcname = request.ptcname;

+        }

+

+        request.children.splice(p_pos, 0, p_childRequest);

+    }

+

+    this.deleteRequest = function(p_requestPath) {

+        var toDeleteIndex = p_requestPath.pop();

+        var parent = this.getRequestFromPath(p_requestPath);

+        if (parent == undefined) {

+            v_fullRequest.splice(toDeleteIndex, 1);

+        } else {

+            var setOrGetData = getOrSetData(parent);

+            parent[setOrGetData].children.splice(toDeleteIndex, 1);

+        }

+    };

+

+    this.convertToSetData = function(p_path) {

+        var request = this.getRequestFromPath(p_path);

+        request.setData = request.getData;

+        request.getData = undefined;

+        request.setData.children = undefined;

+        request.setData.selection = undefined;

+        request.setData.filter = undefined;

+        request.setData.rangeFilter = undefined;

+        request.setData.writableInfo = undefined;

+        request.setData.timeline = undefined;

+        request.setData.content = "";

+        request.setData.tp = 0;

+    };

+

+    this.convertToGetData = function(p_path) {

+        var request = this.getRequestFromPath(p_path);

+        request.getData = request.setData;

+        request.setData = undefined;

+        request.getData.content = undefined;

+        request.getData.tp = undefined;

+    };

+

+    this.getRequest = function() {

+        return v_fullRequest;

+    };

+

+    this.getRequestFromPath = function(p_path) {

+        var request = v_fullRequest[p_path[0]];

+        for (var i = 1; i < p_path.length; ++i) {

+            request = request[getOrSetData(request)].children[p_path[i]];

+        }

+        return request;

+    };

+

+    function getHelpDataElement(p_helpPath) {

+        var source = v_help.sources[p_helpPath[0]];

+        var dataElement = source.dataElements[p_helpPath[1]];

+        for (var i = 2; i < p_helpPath.length; ++i) {

+            dataElement = dataElement.children[p_helpPath[i]];

+        }

+        return {

+            "source" : source,

+            "dataElement" : dataElement

+        };

+    }

+

+    function generateGetData(p_helpPath, p_requestPath, p_filtersThatCanBeParams) {

+        var element = getHelpDataElement(p_helpPath);

+        var getData = {

+            "getData" : {

+                "source" : element.source.source,

+                "element" : element.dataElement.dataElement.name,

+                "params" : getParamsForRequest(p_helpPath, p_requestPath, p_filtersThatCanBeParams)

+            }

+        };

+        return getData;

+    }

+

+    ///////////////////// FILTERS //////////////////////////////

+

+    this.getFilterPart = function(p_requestPath, p_filterPath) {

+        var request = v_this.getRequestFromPath(p_requestPath);

+        var filter;

+        if (request.getData)

+            filter = request.getData.filter;

+        else

+            filter = request.setData.filter;

+        if (p_filterPath.length == 0) {

+            return filter;

+        } else {

+            var i = 0;

+            while (i < p_filterPath.length - 1) {

+                if (filter.request.params == undefined || filter.request.params[p_filterPath[i]] == undefined) {

+                    filter = filter.request.remapTo;

+                } else {

+                    filter = filter.request.params[p_filterPath[i]].paramValue;

+                }

+                ++i;

+            }

+            if (filter.request.params == undefined || filter.request.params[p_filterPath[i]] == undefined) {

+                return filter.request.remapTo;

+            } else {

+                return filter.request.params[p_filterPath[i]].paramValue;

+            }

+        }

+    };

+

+    this.getFilterPartCopy = function(p_requestPath, p_filterPath) {

+        var filter = mcopy(v_this.getFilterPart(p_requestPath, p_filterPath));

+        if (filter.request != undefined) {

+            delete filter.request.params;

+            delete filter.request.remapTo;

+        }

+        return filter;

+    };

+

+    function changeFilterPart(p_requestPath, p_filterPath, p_changeTo, p_paramName, p_change) {

+        var request = v_this.getRequestFromPath(p_requestPath);

+        var filtercontainer;

+        if (request.getData)

+            filtercontainer = request.getData;

+        else

+            filtercontainer = request.setData;

+        if (p_filterPath.length == 0) {

+            filtercontainer.filter = p_changeTo;

+        } else {

+            var filter = filtercontainer.filter;

+            var i = 0;

+            while (i < p_filterPath.length - 1) {

+                if (filter.request.params == undefined || filter.request.params[p_filterPath[i]] == undefined) {

+                    filter = filter.request.remapTo;

+                } else {

+                    filter = filter.request.params[p_filterPath[i]].paramValue;

+                }

+                ++i;

+            }

+            if (p_paramName == "remapTo" || (p_change && (filter.request.params == undefined || filter.request.params[p_filterPath[i]] == undefined))) {

+                filter.request.remapTo = p_changeTo;

+            } else {

+                if (filter.request.params == undefined) {

+                    filter.request.params = [];

+                }

+                if (filter.request.params[p_filterPath[i]] == undefined) {

+                    filter.request.params[p_filterPath[i]] = {};

+                }

+                if (p_paramName != undefined) {

+                    filter.request.params[p_filterPath[i]].paramName = p_paramName;

+                }

+                filter.request.params[p_filterPath[i]].paramValue = p_changeTo;

+            }

+        }

+    }

+

+    function deleteFilterPart(p_requestPath, p_filterPath) {

+        var request = v_this.getRequestFromPath(p_requestPath);

+        var filtercontainer;

+        if (request.getData)

+            filtercontainer = request.getData;

+        else

+            filtercontainer = request.setData;

+        if (p_filterPath.length == 0) {

+            filtercontainer.filter = undefined;

+        } else {

+            var filter = filtercontainer.filter;

+            var i = 0;

+            while (i < p_filterPath.length - 1) {

+                if (filter.request.params == undefined || filter.request.params[p_filterPath[i]] == undefined) {

+                    filter = filter.request.remapTo;

+                } else {

+                    filter = filter.request.params[p_filterPath[i]].paramValue;

+                }

+                ++i;

+            }

+            if (filter.request.params == undefined || filter.request.params[p_filterPath[i]] == undefined) {

+                filter.request.remapTo = undefined;

+            } else {

+                filter.request.params.splice(p_filterPath[i], 1);

+            }

+        }

+    }

+

+    this.addFilterPart = function(p_requestPath, p_filterPath, p_paramName) {

+        changeFilterPart(p_requestPath, p_filterPath, {"dataValue": "true"}, p_paramName, false);

+    };

+

+    this.deleteFilterPart = function(p_requestPath, p_filterPath) {

+        deleteFilterPart(p_requestPath, p_filterPath);

+    };

+

+    this.changeParamNameOfFilterRequest = function(p_requestPath, p_filterPath, p_paramName) {

+        var changeTo = v_this.getFilterPart(p_requestPath, p_filterPath);

+        changeFilterPart(p_requestPath, p_filterPath, changeTo, p_paramName, true);

+    };

+

+    this.convertFilterPartToRequest = function(p_requestPath, p_filterPath, p_helpPath) {

+        var filterRequest = generateGetData(p_helpPath, p_requestPath, getFiltersThatCanParams(p_requestPath, p_filterPath)).getData;

+        if (filterRequest.params != undefined) {

+            for (var i = 0; i < filterRequest.params.length; ++i) {

+                filterRequest.params[i].paramValue = {"dataValue": filterRequest.params[i].paramValue};

+            }

+        }

+

+        changeFilterPart(p_requestPath, p_filterPath, {"request": filterRequest}, undefined, true);

+    };

+

+    this.convertFilterPartToDataValue = function(p_requestPath, p_filterPath, p_newValue) {

+        changeFilterPart(p_requestPath, p_filterPath, {"dataValue": p_newValue}, undefined, true);

+    };

+

+    function getFiltersThatCanParams(p_requestPath, p_filterPath) {

+        var filters = [];

+        var filterrq = v_this.getRequestFromPath(p_requestPath);

+        var filter = filterrq[getOrSetData(filterrq)].filter;

+        if (p_filterPath.length > 0) {

+            for (var i = 0; i < p_filterPath.length - 1; ++i) {

+                if (filter.request.params == undefined || filter.request.params[p_filterPath[i]] == undefined) {

+                    filters.push({'getData': filter.request});

+                    filter = filter.request.remapTo;

+                } else {

+                    filters.push(undefined);

+                    filter = filter.request.params[p_filterPath[i]].paramValue;

+                }

+            }

+        }

+        return filters;

+    }

+

+    this.isValidToConvertFilterToRequest = function(p_requestPath, p_filterPath, p_helpPath) {

+        return p_helpPath.length > 1 && v_this.getFilterPart(p_requestPath, p_filterPath).request == undefined && checkIfAllReferencesFound(getParamsForRequest(p_helpPath, p_requestPath, getFiltersThatCanParams(p_requestPath, p_filterPath)));

+    };

+

+    this.isValidToAddParamToFilterRequest = function(p_requestPath, p_filterPath) {

+        var filterPathCopy = mcopy(p_filterPath);

+        filterPathCopy.pop();

+        if (v_this.getFilterPart(p_requestPath, filterPathCopy).request != undefined) {

+            return true;

+        } else {

+            return false;

+        }

+    };

+

+    ///////////////////// VALIDATION AND PARAMETER SEARCHING //////////////////////////////

+

+    function doesNotHaveGetDataOnPath(p_requestPath) {

+        if (p_requestPath.length == 0) {

+            return false;

+        }

+        var request = v_fullRequest[p_requestPath[0]];

+        if (request.getData == undefined) {

+            return true;

+        }

+        for (var i = 1; i < p_requestPath.length; ++i) {

+            request = request.getData.children[p_requestPath[i]];

+            if (request.getData == undefined) {

+                return true;

+            }

+        }

+        return false;

+    }

+

+    this.isValidToAddRequest = function(p_helpPath, p_requestPath) {

+        if (p_helpPath.length < 2 || p_requestPath.length === 0 || doesNotHaveGetDataOnPath(p_requestPath)) {

+            return false;

+        } else {

+            return checkIfAllReferencesFound(getParamsForRequest(p_helpPath, p_requestPath));

+        }

+    };

+

+    this.isValidToCreateRequest = function(p_helpPath) {

+        if (p_helpPath.length < 2) {

+            return false;

+        } else {

+            var helpParams = getHelpParamsFromPath(p_helpPath);

+            if (helpParams == undefined || helpParams.length === 0) {

+                return true;

+            } else {

+                var requestParams = createParamSkeleton(helpParams);

+                return checkIfAllReferencesFound(requestParams);

+            }

+        }

+    };

+

+    function getParamsForRequest(p_helpPath, p_requestPath, p_filtersThatCanBeParams) {

+        var helpParams = getHelpParamsFromPath(p_helpPath);

+        if (helpParams == undefined || helpParams.length === 0) {

+            return undefined;

+        }

+

+        var requestParams = createParamSkeleton(helpParams);

+        if (checkIfAllReferencesFound(requestParams)) {

+            return requestParams;

+        }

+

+        tarverseHelpBranch(p_helpPath, p_requestPath, requestParams, helpParams, p_filtersThatCanBeParams);

+        if (checkIfAllReferencesFound(requestParams)) {

+            return requestParams;

+        }

+

+        for (var i = 0; i < v_help.sources.length; ++i) {

+            traverseFullHelp(v_help.sources[i].dataElements, p_requestPath, requestParams, helpParams, p_filtersThatCanBeParams);

+            if (checkIfAllReferencesFound(requestParams)) {

+                return requestParams;

+            }

+        }

+

+        return requestParams;

+    }

+

+    function getHelpParamsFromPath(p_helpPath) {

+        var element = getHelpDataElement(p_helpPath);

+        return element.dataElement.dataElement.parameters;

+    }

+

+    function checkIfAllReferencesFound(p_requestParams) {

+        if (p_requestParams == undefined) {

+            return true;

+        }

+        for (var i = 0; i < p_requestParams.length; ++i) {

+            if (p_requestParams[i].paramValue == undefined) {

+                return false;

+            }

+        }

+        return true;

+    }

+

+    function createParamSkeleton(p_helpParams) {

+        var paramList = [];

+        for (var i = 0; i < p_helpParams.length; ++i) {

+            var paramName = p_helpParams[i].name;

+            var paramValue;

+            if (p_helpParams[i].typeDescriptor != undefined && p_helpParams[i].typeDescriptor.reference != undefined) {

+                paramList.push({

+                    "paramName" : paramName

+                });

+            } else if (p_helpParams[i].exampleValue != undefined) {

+                paramList.push({

+                    "paramName" : paramName,

+                    "paramValue" : p_helpParams[i].exampleValue

+                });

+            } else {

+                paramList.push({

+                    "paramName" : paramName,

+                    "paramValue" : ""

+                });

+            }

+        }

+        return paramList;

+    }

+

+    function tarverseHelpBranch(p_helpPath, p_requestPath, p_requestParams, p_helpParams, p_filtersThatCanBeParams) {

+        var source = v_help.sources[p_helpPath[0]];

+        var dataElement = source.dataElements[p_helpPath[1]];

+        checkDataElementInParams(dataElement, p_requestPath, p_requestParams, p_helpParams, p_filtersThatCanBeParams);

+

+        for (var i = 2; i < p_helpPath.length; ++i) {

+            dataElement = dataElement.children[p_helpPath[i]];

+            checkDataElementInParams(dataElement, p_requestPath, p_requestParams, p_helpParams, p_filtersThatCanBeParams);

+        }

+    }

+

+    function traverseFullHelp(p_dataElementList, p_requestPath, p_requestParams, p_helpParams, p_filtersThatCanBeParams) {

+        for (var i = 0; i < p_dataElementList.length; ++i) {

+            var dataElement = p_dataElementList[i];

+            checkDataElementInParams(dataElement, p_requestPath, p_requestParams, p_helpParams, p_filtersThatCanBeParams);

+            if (p_dataElementList[i].children != undefined) {

+                traverseFullHelp(p_dataElementList[i].children, p_requestPath, p_requestParams, p_helpParams);

+            }

+        }

+    }

+

+    function checkDataElementInParams(p_dataElement, p_requestPath, p_requestParams, p_helpParams, p_filtersThatCanBeParams) {

+        for (var i = 0; i < p_requestParams.length; ++i) {

+            if (p_requestParams[i].paramValue == undefined && p_dataElement.dataElement.typeDescriptor != undefined && p_dataElement.dataElement.typeDescriptor.typeName === p_helpParams[i].typeDescriptor.reference.typeName) {

+                checkDataElementOnRequestPath(p_dataElement, p_requestPath, p_requestParams[i], p_filtersThatCanBeParams);

+            }

+        }

+    }

+

+    function checkDataElementOnRequestPath(p_dataElement, p_requestPath, p_param, p_filtersThatCanBeParams) {

+        var request = v_fullRequest[p_requestPath[0]];

+        if (request == undefined) {

+            return;

+        }

+        if (checkDataCorrespondance(p_dataElement, request)) {

+            p_param.paramValue = "%Parent0%";

+        }

+        for (var i = 1; i < p_requestPath.length; ++i) {

+            if (request.getData)

+                request = request.getData.children[p_requestPath[i]];

+            else if (request.setData)

+                request = request.setData.children[p_requestPath[i]];

+            if (checkDataCorrespondance(p_dataElement, request)) {

+                p_param.paramValue = "%Parent" + i +"%";

+                return;

+            }

+        }

+        if (p_filtersThatCanBeParams != undefined) {

+            for (var i = 0; i < p_filtersThatCanBeParams.length; ++i) {

+                request = p_filtersThatCanBeParams[i];

+                if (request != undefined && checkDataCorrespondance(p_dataElement, request)) {

+                    p_param.paramValue = "%FilterParent" + i +"%";

+                    return;

+                }

+            }

+        }

+    }

+

+    /**

+        Check if actual request equals actual help dataelement, which is true if their name is equal and they have the same parameters.

+    */

+    function checkDataCorrespondance(p_dataElement, p_request) {

+        var setOrGetData = getOrSetData(p_request);

+        var ok = p_dataElement.dataElement.name === p_request[setOrGetData].element;

+        if (p_dataElement.dataElement.parameters == undefined || p_dataElement.dataElement.parameters.length === 0) {

+            return ok && (p_request[setOrGetData].params == undefined || p_request[setOrGetData].params.length === 0);

+        }

+        for (var i = 0; i < p_dataElement.dataElement.parameters.length && ok; ++i) {

+            var helpParam = p_dataElement.dataElement.parameters[i];

+            ok = ok && p_request[setOrGetData].params != undefined && p_request[setOrGetData].params[i] != undefined && helpParam.name === p_request[setOrGetData].params[i].paramName;

+        }

+        return ok;

+    }

+

+    ///////////////////// MOVING REQUEST IN THE TREE //////////////////////////////

+

+    this.isValidToMoveRequest = function(p_fromPath, p_toPath) {

+        var fromRequest = v_this.getRequestFromPath(p_fromPath);

+

+        var fromParentPath = mcopy(p_fromPath);

+        fromParentPath.pop();

+

+        if (hasPrefix(p_toPath, fromParentPath)) {

+            return true;

+        } else if (hasPrefix(p_fromPath, p_toPath)) {

+            var allowedParentsLessThan = p_toPath.length;

+            var currentDepth = p_fromPath.length - 1;

+            return checkAllowedParents(fromRequest, allowedParentsLessThan, currentDepth);

+        } else {

+            return false;

+        }

+    };

+

+    function findMaxParent(str) {

+        var pattern = new RegExp(PATTERN);

+        var max = 0;

+        var match = pattern.exec(str);

+        if (match == undefined) {

+            return undefined;

+        }

+        while (match != undefined) {

+            if (match[1] > 0 && match[1] > max) {

+                max = match[1];

+            }

+            match = pattern.exec(str);

+        }

+        return max;

+    }

+

+    function checkAllowedParents(request, allowedParentsLessThan, currentDepth) {

+        var str = JSON.stringify(request);

+        var maxparent = findMaxParent(str);

+        if (maxparent != undefined && maxparent >= allowedParentsLessThan && maxparent < currentDepth) {

+            return false;

+        } else {

+            return true

+        }

+    }

+

+    function getOrSetData(request) {

+        var setOrGetData = "getData";

+        if (request && request.setData)

+            setOrGetData = "setData";

+        return setOrGetData;

+    }

+    this.moveRequest = function(p_fromPath, p_toPath, p_position) {

+        var futureSiblingList;

+        if (p_toPath.length == 0) {

+            futureSiblingList = v_fullRequest;

+        } else {

+            var toParent = v_this.getRequestFromPath(p_toPath);

+            toParent = toParent[getOrSetData(toParent)];

+            if (toParent.children == undefined) {

+                toParent.children = [];

+            }

+            futureSiblingList = toParent.children;

+        }

+

+        var request;

+        var fromParentPath = mcopy(p_fromPath);

+        var fromId = fromParentPath.pop();

+        if (fromParentPath.length == 0) {

+            request = v_fullRequest.splice(fromId, 1)[0];

+        } else {

+            var fromParent = v_this.getRequestFromPath(fromParentPath);

+            fromParent = fromParent[getOrSetData(fromParent)];

+            request = fromParent.children.splice(fromId, 1)[0];

+            if (fromParent.children.length == 0 && fromParent.children != futureSiblingList) {

+                fromParent.children = undefined;

+            }

+        }

+

+        if (p_position > fromId && p_toPath.length === p_fromPath.length -1) {

+            --p_position;

+        }

+        futureSiblingList.splice(p_position, 0, request);

+

+        var fromDepth = p_fromPath.length - 1;

+        var changeBy = p_toPath.length - (p_fromPath.length - 1);

+        updateRequestParams(request, fromDepth, changeBy);

+    };

+

+    function incrementBy(str, fromDepth, amount, regex, suffix) {

+        var pattern = new RegExp(regex);

+        var match = pattern.exec(str);

+        var radix = 10;

+        var parentid = parseInt(match[1], radix);

+        if (parentid >= fromDepth) {

+            return "%Parent" + (parseInt(match[1], radix) + amount) + suffix + "%";

+        } else {

+            return str;

+        }

+    }

+

+    function incrementParentBy(str, fromDepth, amount) {

+        return incrementBy(str, fromDepth, amount, PATTERN, "");

+    }

+

+    function incrementParentIndexBy(str, fromDepth, amount) {

+        return incrementBy(str, fromDepth, amount, PATTERN_IDX, "::idx");

+    }

+

+    function updateRequestParams(request, fromDepth, changeBy) {

+        var setOrGetData = getOrSetData(request);

+        var string = JSON.stringify(request[setOrGetData]);

+        string = string.replace(new RegExp(PATTERN_IDX), function(match) {return incrementParentIndexBy(match, fromDepth, changeBy);});

+        string = string.replace(new RegExp(PATTERN), function(match) {return incrementParentBy(match, fromDepth, changeBy);});

+        request[setOrGetData] = JSON.parse(string);

+    }

+}

diff --git a/htdocs/Utils/TaskUtils.js b/htdocs/Utils/TaskUtils.js
new file mode 100644
index 0000000..94872ad
--- /dev/null
+++ b/htdocs/Utils/TaskUtils.js
@@ -0,0 +1,236 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GenericTask(p_function) {

+    "use strict";

+    this.taskOperation = p_function;

+}

+

+/**

+    @param p_tasks: the list of tasks. Each task must have a taskOperation method.

+    @param callback: a callback function, callback(boolean success, string errorMessage) will be called when all tasks finish.

+*/

+function SyncTaskList(p_tasks, p_callback) {

+    "use strict";

+    var v_tasks = p_tasks;

+    var v_counter = -1;

+    var v_finished = false;

+    var v_success = true;

+    var v_data = [];

+

+    this.taskOperation = function() {

+        if (!v_finished) {

+            callback(true);

+        }

+    };

+

+    function callback(ok, data) {

+        if (ok && data != undefined) {

+            v_data[v_counter] = data;

+        }

+        if (!ok) {

+            v_success = false;

+            v_data[v_counter] = data;

+            p_callback(v_success, v_data);

+        } else if (v_counter === v_tasks.length - 1) {

+            v_finished = true;

+            p_callback(v_success, v_data);

+        } else {

+            v_counter++;

+            var task = v_tasks[v_counter];

+            if (task.taskOperation != undefined) {

+                task.taskOperation(callback);

+            } else {

+                if (window.console) console.error("No executable method found! " + Object.prototype.toString(task));

+            }

+        }

+    }

+

+    this.extend = function(p_tasks) {

+        for (var i = 0; i < p_tasks.length; ++i) {

+            v_tasks.push(p_tasks[i]);

+        }

+    };

+

+    this.push = function(p_task) {

+        v_tasks.push(p_task);

+    };

+}

+

+

+/**

+    @param p_tasks: the list of tasks. Each task must have a taskOperation method.

+    @param callback: a callback function, callback(boolean success, string errorMessage) will be called when all tasks finish.

+*/

+function TaskList(p_tasks, p_callback) {

+    "use strict";

+    var v_tasks = p_tasks;

+    var v_callback = p_callback;

+    var v_counter = v_tasks.length;

+    var v_finished = false;

+    var v_success = true;

+    var v_data = [];

+

+    function CTaskObject(index) {

+        var taskIndex = index;

+        this.callback = function(ok, data) {

+            v_data[taskIndex] = data;

+            v_counter--;

+

+            if (!ok) {

+                v_success = false;

+            }

+            checkStatus();

+        };

+    }

+

+    this.taskOperation = function() {

+        checkStatus();

+        if (!v_finished) {

+            for (var i = 0; i < v_tasks.length; ++i) {

+                if (v_tasks[i].taskOperation != undefined) {

+                    v_tasks[i].taskOperation(new CTaskObject(i).callback);

+                } else {

+                    if (window.console) console.error("No executable method found! " + Function.prototype.toString(v_tasks[i]));

+                }

+            }

+        }

+    };

+

+    function checkStatus() {

+        if (v_counter === 0) {

+            v_finished = true;

+            if (v_callback)

+                v_callback(v_success, v_data);

+        }

+    }

+

+    this.extend = function(p_tasks) {

+        for (var i = 0; i < p_tasks.length; ++i) {

+            v_tasks.push(p_tasks[i]);

+            ++v_counter;

+        }

+    };

+

+    this.push = function(p_task) {

+        v_tasks.push(p_task);

+        ++v_counter;

+    };

+}

+

+function JsImportTask(p_file, p_fileHandler) {

+    "use strict";

+    var v_file = p_file;

+    var v_fileHandler = p_fileHandler;

+    this.taskOperation = function(callback) {

+        v_fileHandler.importJsFile(v_file, callback);

+    };

+}

+

+function ListDirectoryTask(p_directory, p_fileHandler) {

+    "use strict";

+    /* path separator is / (like in the urls or the comment char) */

+    var v_directory = p_directory;

+    var v_fileHandler = p_fileHandler;

+    this.taskOperation = function(callback) {

+        function dirArrived(directories) {

+            callback(true, directories);

+        }

+        v_fileHandler.getDirectory(v_directory, dirArrived);

+    };

+}

+

+function JsonSaveTask(loader, name) {

+    var v_loader = loader;

+    var v_name = name;

+    this.taskOperation = function(callback) {

+        v_loader.save(v_name, callback);

+    };

+}

+

+function FileSaveTask(loader, content, name) {

+    var v_loader = loader;

+    var v_content = content;

+    var v_name = name;

+    this.taskOperation = function(callback) {

+        v_loader.save(v_content, v_name, callback);

+    };

+}

+

+function JsImportTaskList(p_files, p_fileHandler, p_callback) {

+    "use strict";

+    var v_fileHandler = p_fileHandler;

+    var tasks = [];

+    for (var i = 0; i < p_files.length; ++i) {

+        tasks.push(new JsImportTask(p_files[i], v_fileHandler));

+    }

+    var taskList = new TaskList(tasks, p_callback);

+    this.taskOperation = function() {

+        taskList.taskOperation();

+    };

+}

+

+function MultipleDirectoryListTask(p_loactions, p_fileHandler) {

+    var v_loactions = p_loactions;

+    var v_fileHandler = p_fileHandler;

+

+    this.taskOperation = function(callback) {

+        function directoriesListed(ok, data) {

+            var jsfiles = [];

+            var cssfiles = [];

+            var htmlfiles = [];

+

+            for (var i = 0; i < data.length; ++i) {

+                var files = data[i];

+                for (var j = 0; j < files.length; ++j) {

+                    var fileName = files[j].fileName;

+                    if (fileName.endsWith(".js")) {

+                        jsfiles.push(fileName);

+                    } else if (fileName.endsWith(".css")) {

+                        cssfiles.push(fileName);

+                    } else if (fileName.endsWith(".html")) {

+                        htmlfiles.push(fileName);

+                    }

+                }

+            }

+

+            callback(ok, {

+                "jsfiles": jsfiles,

+                "cssfiles": cssfiles,

+                "htmlfiles": htmlfiles

+            });

+        }

+

+        var tasks = [];

+        for (var i = 0; i < v_loactions.length; ++i) {

+            tasks.push(new ListDirectoryTask(v_loactions[i], v_fileHandler));

+        }

+

+        new TaskList(tasks, directoriesListed).taskOperation();

+    }

+}

+

+function JsImportFromConfigTask(p_configPath, p_fileHandler) {

+    var v_fileHandler = p_fileHandler;

+    var v_configPath = p_configPath;

+    var v_callback;

+

+    function configLoaded(ok, config) {

+        function imported(ok) {

+            v_callback(ok, config.apiExtension);

+        }

+

+        if (ok && config.filesToInclude != undefined) {

+            new JsImportTaskList(config.filesToInclude, v_fileHandler, imported).taskOperation();

+        } else {

+            v_callback(true, config.apiExtension);

+        }

+    }

+

+    this.taskOperation = function(callback) {

+        v_callback = callback;

+        new JsonLoader(v_configPath, v_fileHandler).taskOperation(configLoaded);

+    };

+}
\ No newline at end of file
diff --git a/htdocs/Utils/Utilities.js b/htdocs/Utils/Utilities.js
new file mode 100644
index 0000000..eea9d4f
--- /dev/null
+++ b/htdocs/Utils/Utilities.js
@@ -0,0 +1,266 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+

+/**

+ * printf() clone - String.prototype.format(formatStr, args...)

+ * @param {string} format - format string

+ * @param {string} args... - arguments to inject

+ * @example

+ * // 'zero 1 blabla lastone'

+ * '{0} {1} blabla {2}'.format("zero", 1, "lastone");

+ * @returns {string} Returns a new string where the arguments are injected into the format string.

+ * You can escape curly beraces '{' by doubling it: '{{0}}: {0}'.format("theargument");

+ */

+String.prototype.format = function() {

+    "use strict";

+    var args = arguments;

+    return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (m, n) {

+        if (m === "{{") { return "{"; }

+        if (m === "}}") { return "}"; }

+        return args[n];

+    });

+};

+

+function uniq(list) {

+    var seen = {};

+    return list.filter(function(item) {

+        return seen.hasOwnProperty(item) ? false : (seen[item] = true);

+    });

+}

+

+window.jsErrors = [];

+

+if (!window.onerror) {

+    window.onerror = function(error, url, line, ch, ex) {

+        "use strict";

+        var errorMessage = 'Error caught in global context: "{0}", URL: {1}, Line {2}, char index {3} (w/o indent, usually).'.format(error, url, line, ch);

+        var stack = "*** Stack *** : " + (ex ? ex.stack : '(No stack available)');

+        if (window.console) { 

+            console.error(errorMessage);

+            console.error(stack);

+        }

+        window.jsErrors[window.jsErrors.length] = errorMessage;

+        window.jsErrors[window.jsErrors.length] = stack;

+        return true; // handled.

+    };

+}

+

+/** mpad - converts a number to string and pads it with leading zeroes */

+function mpad(num, size) {

+    "use strict";

+    return ('000000000' + num).substr(-size);

+}

+

+/** mlog - logs values to the debug console. Freezez objects to the current vlaue, unlike the native console. */

+function mlog() {

+    "use strict";

+    var obj=[];

+    for (var i = 0; i < arguments.length; i++) {

+        if (arguments[i] == undefined) {

+            obj[i] = undefined;

+        } else {

+            obj[i] = mcopy(arguments[i]);

+        }

+    }

+    if (window.console) console.log(obj);

+}

+

+/** mlog - logs values to the debug console. Freezez objects to the current vlaue, unlike the native console. Also prints call stack */

+function mlogc() {

+    "use strict";

+    var obj=[];

+    for (var i = 0; i < arguments.length; i++) {

+        if (arguments[i] == undefined) {

+            obj[i] = undefined;

+        } else {

+            obj[i] = mcopy(arguments[i]);

+        }

+    }

+    if (window.console) console.log("CALL STACK :" + new Error().stack, obj);

+}

+

+/** mcopy - copies an object through serialization and deserializaton. */

+function mcopy(data) {

+    "use strict";

+    return JSON.parse(JSON.stringify(data));

+}

+/*

+// ONLY enable these if you need them in multiple places.

+Array.prototype.mshift = function(times) {

+    for (var i = 0; i < times; i++) {

+        this.shift();

+    }

+};

+

+Array.prototype.mpop = function(times) {

+    for (var i = 0; i < times; i++) {

+        this.pop();

+    }

+};

+*/

+

+/**

+ * Replace all occurences of str1 to str2, inside str.

+ * @param {string} str - source

+ * @param {string} str1 - from

+ * @param {string} str2 - to

+ * @returns {string} Returns with the replaced string.

+ */

+function replaceAll(str, str1, str2) {

+   "use strict";

+   var index = str.indexOf(str1);     

+   while (index !== -1) {

+      str = str.replace(str1, str2);

+      index = str.indexOf(str1);

+   }

+   return str;

+}

+

+/**

+ * Pretty prints a JSON serialized string. Contains workarounds for oldff.

+ * @param {string} text - JSON text

+ * @param {number} indent - Number of spaces to indent

+ * @returns {string} Returns with the JSON string with the proper indent, or null if input is not a valid JSON textual representation.

+ */

+function indentJSON(text, indent) {

+    "use strict";

+    var anObj;

+    var indentStep = indent || 4;

+    try {

+        anObj = JSON.parse(text);

+        var str = JSON.stringify(anObj, undefined, indentStep);

+        if (oldff) // There is a strange formatting issue: "[{" is the sequence, and is not newline+indented.

+            str = str.replace(/^(\s*).*?(?:\[\{)/gm,

+                function(match, p1) {

+                    var indent = "\r\n";

+                    for(var i = 0; i < indentStep; i++)

+                        indent += ' ';

+                    return match.replace("[{", "[" + indent + p1 + "{");

+                });

+        return str;

+    } catch (e) {

+        return null;

+    }

+}

+

+/**

+ * Shallow Copy of an object.

+ * @param {object} obj - object to clone

+ * @returns {object} Returns with a new object where the field have their values cloned.

+ */

+function shallowcopy(obj) {

+    "use strict";

+    var target = {};

+    for (var i in obj) {

+        if (obj.hasOwnProperty(i)) {

+            target[i] = obj[i];

+        }

+    }

+    return target;

+}

+

+/**

+ * Create an Event object.

+ * @param {string} p_name - Name of the event

+ * @returns {Event} Returns with a new, initialized Event.

+ */

+function createEvent(p_name) {

+    "use strict";

+    if (oldff) {

+        var v_event = document.createEvent('Event');

+        v_event.initEvent(p_name, true, true);

+        return v_event;

+    } else

+        return new Event(p_name);

+}

+

+/**

+ * Generates a sufficiently unique ID to be used in the DOM.

+ * @returns {string} Returns with a new, random ID.

+ */

+function generateId() {

+    "use strict";

+    return String.fromCharCode(65 + Math.floor(Math.random() * 26) + (Math.round(Math.random()) ? 32 : 0)) + Date.now();

+}

+

+/**

+ * Deep Copy of an object.

+ * @param {object} obj - object to clone

+ * @returns {object} Returns with a new object where everything is fully cloned.

+ */

+function instanceToObject(obj) {

+    "use strict";

+    var o = {};

+    for (var property in obj) {

+        if (obj.hasOwnProperty(property)) {

+            if (typeof obj[property] === "object") {

+                o[property] = instanceToObject(obj[property]);

+            } else {

+                o[property] = obj[property];

+            }

+        }

+    }

+    return o;

+}

+

+/** isvalue returns true only if the parameter is not undefined and is not null. */

+function isvalue(aSomething) {

+    "use strict";

+    return !((typeof aSomething === 'undefined') || (aSomething === null));

+}

+

+String.prototype.splice = function(index, count, add) {

+    return this.slice(0, index) + (add || "") + this.slice(index + count);

+}

+

+function hasPrefix(list, prefix) {

+    for (var i = 0; i < prefix.length; ++i) {

+        if (list[i] == undefined || list[i] != prefix[i]) {

+            return false;

+        }

+    }

+    return true;

+}

+

+function transpose(matrix) {

+    if (matrix.length == 0) return matrix;

+    return matrix[0].map(function(col, i) { 

+        return matrix.map(function(row) { 

+            return row[i];

+        })

+    });

+}

+

+function getLocationParam(p_key) {

+    var pairs = location.search.substring(1).split('&');

+    for (var i = 0; i < pairs.length; ++i) {

+        var keyValue = pairs[i].split('=');

+        if (keyValue[0] == p_key) {

+            return keyValue[1].replace('/', '');

+        }

+    }

+    return undefined;

+}

+

+// string.encode("hex")

+function hex2a(hex) {

+    var str = '';

+    for (var i = 0; i < hex.length; i += 2)

+        str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));

+    return str;

+}

+

+// string.decode("hex")

+function a2hex(str) {

+    var arr = [];

+    for (var i = 0, l = str.length; i < l; i++) {

+        var hex = Number(str.charCodeAt(i)).toString(16);

+        arr.push(hex.length > 1 && hex || "0" + hex);

+    }

+    return arr.join('');

+}

+

+//# sourceURL=Utils\Utilities.js

diff --git a/htdocs/Utils/ViewUtils.js b/htdocs/Utils/ViewUtils.js
new file mode 100644
index 0000000..d77d5ee
--- /dev/null
+++ b/htdocs/Utils/ViewUtils.js
@@ -0,0 +1,579 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function BaseDialog(p_parentId, p_id, p_options) {

+    "use strict";

+

+    var v_id = p_id;

+    var v_parentId = p_parentId;

+    var v_options = p_options;

+

+    var v_this = this;

+    var v_defaultButtonId;

+

+    $("#" + v_parentId).append('<div id="' + v_id + '"></div>');

+    var dialog = $("#" + v_id);

+

+    this.createDialogContent = function() {};

+

+    this.setDefaultButton = function(id) {

+        v_defaultButtonId = id;

+    };

+

+    this.createButtons = function() {

+        return [];

+    };

+

+    this.onClosing = function() {};

+

+    this.close = function() {

+        dialog.dialog("close");

+    };

+

+    function createDialogWindow() {

+        if (v_options.height == undefined) {

+            v_options.height = "auto";

+        }

+

+        if (v_options.width == undefined) {

+            v_options.width = "auto";

+        }

+

+        dialog.dialog({

+            autoOpen: false,

+            height: v_options.height,

+            width: v_options.width,

+            modal: true,

+            title: v_options.header,

+            buttons: v_this.createButtons(),

+

+            close: function(event, ui) {

+                v_this.onClosing();

+                $("#" + v_id).remove();

+            }

+        });

+    }

+

+    this.contentCreated = function() {};

+

+    this.open = function() {

+        this.createDialogContent();

+        createDialogWindow();

+        this.contentCreated();

+

+        if (v_defaultButtonId != undefined) {

+            dialog.on('keydown', function(e) {

+                var code = (e.keyCode ? e.keyCode : e.which);

+                if (code === $.ui.keyCode.ENTER) {

+                    e.stopPropagation();

+                    $('#' + v_defaultButtonId).click();

+                    return false;

+                }

+            });

+        }

+

+        dialog.dialog("open");

+    };

+}

+

+function ExitDialog(p_parentId, p_id, p_options) {

+    "use strict";

+    var dialog = new BaseDialog(p_parentId, p_id, p_options);

+

+    var v_id = p_id;

+    var v_options = p_options;

+    var v_callback = p_options.callback;

+    var v_exit = false;

+    var v_save = false;

+

+    dialog.createDialogContent = function() {

+        $("#" + v_id).append('<p class="validateTips">' + v_options.text + '</p>');

+    };

+

+    dialog.onClosing = function() {

+        v_callback(v_exit, v_save);

+    };

+

+    dialog.createButtons = function() {

+        dialog.setDefaultButton(v_id + "_YesButton");

+        return [

+            {

+                text: "Yes",

+                id: v_id + "_YesButton",

+                click:  function () {

+                    v_exit = true;

+                    v_save = true;

+                    dialog.close();

+                }

+            },

+            {

+                text: "No",

+                id: v_id + "_NoButton",

+                click:  function () {

+                    v_exit = true;

+                    v_save = false;

+                    dialog.close();

+                }

+            },

+            {

+                text: "Cancel",

+                id: v_id + "_CancelButton",

+                click:  function () {

+                    v_exit = false;

+                    v_save = false;

+                    dialog.close();

+                }

+            }

+        ];

+    };

+

+    return dialog;

+}

+

+function ConfirmationDialog(p_parentId, p_id, p_options) {

+    "use strict";

+    var dialog = new BaseDialog(p_parentId, p_id, p_options);

+

+    var v_id = p_id;

+    var v_options = p_options;

+    var v_callback = p_options.callback;

+

+    dialog.createDialogContent = function() {

+        $("#" + v_id).append('<p class="validateTips">' + v_options.text + '</p>');

+    };

+

+    dialog.createButtons = function() {

+        dialog.setDefaultButton(v_id + "_OkButton");

+        return [

+            {

+                text: "OK",

+                id: v_id + "_OkButton",

+                click:  function () {

+                    $("#" + v_id).dialog("close");

+                    v_callback();

+                }

+            }

+        ];

+    };

+

+    return dialog;

+}

+

+function InputDialog(p_parentId, p_id, p_options) {

+    "use strict";

+    var dialog = new BaseDialog(p_parentId, p_id, p_options);

+

+    var v_id = p_id;

+    var v_options = p_options;

+    var v_validator = v_options.validator;

+    var v_callback = v_options.callback;

+

+    var v_formId = v_id + "_Form";

+    var v_fieldId = v_id + "_Field";

+    var v_default = p_options.defaultValue;

+    var v_validationId = v_id + '_Validation';

+

+    dialog.createDialogContent = function() {

+        var htmlContent = '<p class="validateTips">' + v_options.text + '</p>';

+        htmlContent += '<form name="' + v_formId + '" id="' + v_formId + '"><input type="text" size="32" id="' + v_fieldId + '" value="' + v_default + '"/><br /><p id="' + v_validationId + '" class="ui-inputdialog-validate"></p><input type="submit" tabindex="-1" style="position:absolute; top:-100px"></form>';

+        $("#" + v_id).append(htmlContent);

+

+        if (v_validator != undefined) {

+            $("#" + v_fieldId).on('keyup', function() {

+                $('#' + v_validationId).html(v_validator($("#" + v_fieldId).val()));

+            });

+        }

+    };

+

+    dialog.createButtons = function() {

+        dialog.setDefaultButton(v_id + "_OkButton");

+        return [

+            {

+                text: "OK",

+                id: v_id + "_OkButton",

+                click:  function () {

+                    var value = $("#" + v_fieldId).val();

+                    if (v_validator == undefined || v_validator(value) === "") {

+                        $("#" + v_id).dialog("close");

+                        v_callback(value);

+                    }

+                }

+            }

+        ];

+    };

+

+    return dialog;

+}

+

+function ChoiceDialog(p_parentId, p_id, p_options) {

+    "use strict";

+    var dialog = new BaseDialog(p_parentId, p_id, p_options);

+

+    var v_id = p_id;

+    var v_options = p_options;

+    var v_choices = v_options.choices;

+    var v_callback = v_options.callback;

+

+    var v_okButtonId = v_id + "_OkButton";

+    var v_tableId = v_id + "_Table";

+

+    function search(input, choices, callback) {

+        var indexes = [];

+        for (var i = 0; i < choices.length; ++i) {

+            if (choices[i].text.indexOf(input) != -1) {

+                indexes.push(i)

+            }

+        }

+

+        callback(indexes);

+    }

+

+    function searchComplete(indexes) {

+        $(".dialog-table tr").addClass("hidden");

+        for (var i = 0; i < indexes.length; ++i) {

+            $(".dialog-table tr:nth-child(" + (indexes[i] + 1) + ")").removeClass("hidden");

+        }

+        $(".validateTips").text(v_options.text);

+    }

+

+    dialog.getTableId = function() {

+        return v_tableId;

+    };

+

+    dialog.getRows = function() {

+        var rows = [];

+        for (var i = 0; i < v_choices.length; ++i) {

+            var radioId = v_id + '_RadioButton_' + v_choices[i].text;

+            rows.push([

+                '<input type="radio" name="class" id="' + radioId + '" value="' + v_choices[i].value + '"/>',

+                '<label for="' + radioId + '">' + v_choices[i].text + '</label>'

+            ]);

+        }

+        return rows;

+    };

+

+    dialog.createDialogContent = function() {

+        var htmlContent = '<p class="validateTips">' + v_options.text + '</p>';

+        htmlContent += '<input class="validateSearch" type="text"><button class="validateSearchButton">Search</button><button class="validateSearchClear">Show All</button>';

+        htmlContent += '<table class="dialog-table" id="' + v_tableId + '">';

+

+        var rows = dialog.getRows();

+        for (var i = 0; i < rows.length; ++i) {

+            htmlContent += '<tr>';

+            for (var j = 0; j < rows[i].length; ++j) {

+                htmlContent += '<td>' + rows[i][j] + '</td>';

+            }

+            htmlContent += '</tr>';

+        }

+

+        htmlContent += '</table>';

+        $("#" + v_id).append(htmlContent);

+

+

+        $(".dialog-table tr").dblclick(function() {

+            $('#' + v_okButtonId).click();

+        });

+

+        $(".validateSearchButton").click(function() {

+            $(".validateTips").text("Searching...");

+            if (v_options.searchFunction != undefined) {

+                v_options.searchFunction($(".validateSearch").val(), v_choices, searchComplete);

+            } else {

+                search($(".validateSearch").val(), v_choices, searchComplete);

+            }

+        });

+

+        $(".validateSearchClear").click(function() {

+            $(".dialog-table tr").removeClass("hidden");

+        });

+

+        $(".validateSearch").on('keydown', function(e) {

+            var code = (e.keyCode ? e.keyCode : e.which);

+            if (code === $.ui.keyCode.ENTER) {

+                e.stopPropagation();

+                $('.validateSearchButton').click();

+                return false;

+            }

+        });

+    };

+

+    dialog.createButtons = function() {

+        dialog.setDefaultButton(v_okButtonId);

+        return [

+            {

+                text: "OK",

+                id: v_okButtonId,

+                click:  function () {

+                    var selection = $("#" + v_tableId + " input[type='radio']:checked").val();

+                    if (selection) {

+                        $("#" + v_id).dialog("close");

+                        $("#" + v_id).remove();

+                        v_callback(selection);

+                    }

+                }

+            }

+        ];

+    };

+

+    return dialog;

+}

+

+function ChoiceDialogWithButton(p_parentId, p_id, p_options) {

+    "use strict";

+    var dialog = new ChoiceDialog(p_parentId, p_id, p_options);

+

+    var v_id = p_id;

+    var v_options = p_options;

+    if (v_options.buttonStyle == undefined) {

+        v_options.buttonStyle = "";

+    }

+    if (v_options.buttonText == undefined) {

+        v_options.buttonText = "?";

+    }

+    var v_choices = v_options.choices;

+

+    dialog.getRows = function() {

+        var rows = [];

+        for (var i = 0; i < v_choices.length; ++i) {

+            var radioId = v_id + '_RadioButton_' + v_choices[i].text;

+            rows.push([

+                '<input type="radio" name="class" id="' + radioId + '" value="' + v_choices[i].value + '"/>',

+                '<label for="' + radioId + '">' + v_choices[i].text + '</label>',

+                '<button style="' + v_options.buttonStyle + '" id="setupDeleteButton_' + i + '" type="button" idx="' + i + '">' + v_options.buttonText + '</button>'

+            ]);

+        }

+        return rows;

+    };

+

+    dialog.contentCreated = function() {

+        $("#" + dialog.getTableId() ).on("click", "button", function() {

+            v_options.buttonHandler(v_choices[parseInt($(this).attr("idx"), 10)].value);

+            if (v_options.closeOnButtonPress) {

+                $("#" + v_id).dialog("close");

+                $("#" + v_id).remove();

+            }

+        });

+    };

+

+    return dialog;

+}

+

+function FileDialog(p_fileHandler, p_parentId, p_id, p_options) {

+

+    var v_id = p_id;

+    var v_options = p_options;

+    var v_fileHandler = p_fileHandler;

+    var v_fileHandlerViewmodel = {"getFileHandler": function() {return v_fileHandler;}};

+    var v_callback = v_options.callback;

+

+    var v_viewmodel = new CViewModel_FileSelector(v_fileHandlerViewmodel, v_options);

+    var v_view = new CView_FileSelector([v_viewmodel], v_id + "_FileSelectorContent", v_id, {});

+

+    if (v_options.height == undefined) {

+        v_options.height = $(window).height() * 0.8;

+    }

+

+    if (v_options.width == undefined) {

+        v_options.width = $(window).width() * 0.8;

+    }

+

+    var dialog = new BaseDialog(p_parentId, p_id, v_options);

+

+    dialog.createDialogContent = function() {

+        $("#" + v_id).append('<p class="validateTips">' + v_options.text + '</p>');

+        v_view.applicationCreated();

+    };

+

+    dialog.createButtons = function() {

+        v_viewmodel.filesSelected = function() {

+            var selection = v_viewmodel.getSelection();

+            if (selection.length > 0) {

+                if (v_options["dialogType"] == "save") {

+                    v_viewmodel.exists(selection[0].value, ifExists)

+                } else {

+                    toReturn();

+                }

+            }

+        }

+

+        v_viewmodel.fileSelectionCanceled = function() {

+            $("#" + v_id).dialog("close");

+        }

+    };

+

+    function ifExists(exists) {

+        if (exists) {

+            if (confirm("File already exists, overwrite it?")) {

+                toReturn();

+            }

+        } else {

+            toReturn();

+        }

+    }

+

+    function toReturn() {

+        $("#" + v_id).dialog("close");

+        v_callback(v_viewmodel.getSelection());

+    }

+

+    return dialog;

+}

+

+var ViewUtils = {};

+

+ViewUtils.jumpToEditor = function(id) {

+    $("#" + id)[0].scrollIntoView({block: "end", behavior: "smooth"});

+};

+

+ViewUtils.applyCss = function(a_customData, a_id) {

+    if (a_customData.css != undefined) {

+        $("#" + a_id).css(a_customData.css);

+    }

+};

+

+ViewUtils.processCss = function(a_customData, a_parentId) {

+    if (a_customData.processCss != undefined) {

+        var cssString = '';

+        for (var selector in a_customData.processCss) {

+            cssString += "#" + a_parentId + " " + selector + " {";

+            for (var rule in a_customData.processCss[selector]) {

+                cssString += rule + ": " + a_customData.processCss[selector][rule] + ";";

+            }

+            cssString += "}\n";

+        }

+        $("#" + a_parentId).prepend("<style type='text/css'>" + cssString + "</style>");

+    }

+};

+

+ViewUtils.getViewmodelsFromExpectedInterface = function(a_viewmodels, a_class) {

+    var viewmodels = [];

+    var expectedInterface = a_class.expectsInterface();

+

+    for (var i = 0; i < expectedInterface.length; ++i) {

+        var interfaceList;

+        if (expectedInterface[i].mandatory != undefined) {

+            interfaceList = expectedInterface[i].mandatory;

+        } else if (expectedInterface[i].optional != undefined) {

+            interfaceList = expectedInterface[i].optional;

+        } else {

+            continue;

+        }

+

+        for (var j = 0; j < a_viewmodels.length; ++j) {

+            var ok = true;

+            for (var k = 0; ok && k < interfaceList.length; ++k) {

+                if (a_viewmodels[j][interfaceList[k]] == undefined) {

+                    ok = false;

+                }

+            }

+            if (ok) {

+                viewmodels[i] = a_viewmodels[j];

+                break;

+            }

+        }

+    }

+

+    return viewmodels;

+};

+

+ViewUtils.addLabel = function(a_id, a_text, a_class) {

+

+    if (a_text == undefined) {

+        a_text = "";

+    }

+

+    if (a_class == undefined) {

+        a_class = "CustomizableApp_LabelAtTop";

+    }

+

+    var obj = $("#" + a_id);

+    var html = '<label class="' + a_class + '">' + a_text + '</label><br/>';

+    obj.prepend(html);

+

+    return $("#" + a_id + " > *").first();

+};

+

+ViewUtils.checkVisibility = function(p_conditionViewmodel, p_id) {

+    var isVisible = p_conditionViewmodel == undefined || p_conditionViewmodel.getState();

+    if (isVisible) {

+        $("#" + p_id).removeClass("hidden");

+        return true;

+    } else {

+        $("#" + p_id).addClass("hidden");

+        return false;

+    }

+};

+

+ViewUtils.getSuggestedHeight = function(id) {

+    var windowHeight = window.innerHeight;

+    var top = 0;

+    var element = document.getElementById(id);

+    while (element != undefined) {

+        top += element.offsetTop || 0;

+        element = element.offsetParent;

+    }

+    return windowHeight - top - 10;

+}

+

+ViewUtils.addTooltip = function(id, customData) {

+    if (customData.tooltip != undefined) {

+        $("#" + id).prop("title", customData.tooltip);

+    }

+}

+

+ViewUtils.commonViewSchema = {

+    "properties": {

+        "flex": {

+            "oneOf": [

+                {

+                    "description": "A number that is used to determine the view's width / height in aligners as a proportion",

+                    "type": "number"

+                },

+                {

+                    "description": "A number that is used to determine the view's width / height in aligners in pixels",

+                    "type": "string",

+                    "pattern": "[0-9]+px"

+                }

+            ]

+        },

+        "css": {

+            "description": 'Css rules for the current div. Example: {"height": "500px"}',

+            "type": "object",

+            "properties": {},

+            "additionalProperties": true

+        },

+        "processCss": {

+            "description": 'Apply the css rules to the css selectors given in the object\'s ids. Handle with care, as the given css is applied to all matched elements below the current element (even in the subviews). Example: {"DIV > LABEL": {"color": "red"}}',

+            "type": "object",

+            "properties": {},

+            "additionalProperties": true

+        }

+    }

+};

+

+ViewUtils.commonElementSchema = {

+    "properties": {

+        "isElementLabelPresent": {

+            "type": "boolean",

+            "format": "checkbox",

+            "default": true,

+            "description": "show label above the element"

+        },

+        "elementText": {

+            "type": "string",

+            "description": "the text of the label above the element (if undefined, the request element will be used)"

+        },

+        "tooltip": {

+            "type": "string",

+            "description": "the tooltip text shown when hovering over the element"

+        },

+        "disabled": {

+            "type": "boolean",

+            "format": "checkbox",

+            "description": "whether the view element is disabled, i.e. not writable",

+            "default": true

+        }

+    }

+};

diff --git a/htdocs/WebApplicationFramework/FrameworkMain.js b/htdocs/WebApplicationFramework/FrameworkMain.js
new file mode 100644
index 0000000..ab9c5e2
--- /dev/null
+++ b/htdocs/WebApplicationFramework/FrameworkMain.js
@@ -0,0 +1,252 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+// Singleton list of applications inherited from WebAppBase.
+// "WebApplications" object is intended to be the only global object.
+// It is filled by each WebApplications/<WebAppDir>/Main.js, when the js is loaded.
+var WebApplications = WebApplications || [];
+
+if (window["$"] == undefined) {
+    var browser = browserCheck();
+    alert('This browser is not supported: ' + browser[0] + ' ' + browser[1] + '\nPlease use at least Firefox 38 or Chrome.');
+}
+
+$(document).ready(function() {
+    "use strict";
+
+    function receiveMessage(event) {
+        if (event.source == parent && event.data.username != undefined && event.data.password != undefined) {
+            localStorage.setItem('username', event.data.username);
+            localStorage.setItem('password', event.data.password);
+        }
+    }
+
+    window.addEventListener("message", receiveMessage, false);
+    window.addEventListener("popstate", function(event) {
+        if (event.state != undefined && event.state.index != undefined && WebApplications[event.state.index] != undefined) {
+            webappBtnClicked(event.state.index, 'applications_header_appBtn_' + event.state.index);
+        }
+    });
+
+    var m_this = this;
+    var m_fileHandler = new FileHandler();
+    var m_webAppModel = new CWebApp_Model(m_fileHandler);
+
+    var m_loadedWebAppIndex;
+
+    this.setAppParam = function(appName, key, value) {
+        var index = getWebAppIndexFromName(appName);
+        if (index != undefined) {
+            var app = WebApplications[index];
+            app.params[key] = value;
+        }
+    };
+
+    this.loadApp = function(appName) {
+        var index = getWebAppIndexFromName(appName);
+        if (index != undefined) {
+            webappBtnClicked(index, 'applications_header_appBtn_' + index, true);
+        } else {
+            alert('No application found with name ' + appName);
+        }
+    };
+
+    function getWebAppIndexFromName(appName) {
+        for (var i = 0; i < WebApplications.length; ++i) {
+            if (WebApplications[i].name == appName) {
+                return i;
+            }
+        }
+    }
+
+    function webappBtnClicked(index, buttonId, storeState) {
+        var webApp = WebApplications[index].application;
+
+        function webappUnloaded(aApplicationUnloaded) {
+            if (aApplicationUnloaded) {
+                if (storeState) {
+                    window.history.pushState({'index': index}, '');
+                }
+                webApp.load(m_webAppModel, WebApplications[index].params, m_this); // calls WebApplications load fuction. WebApplications are derived from WebAppBase
+                m_loadedWebAppIndex = index;
+
+                $('#applications_header BUTTON').removeClass('SelectedWebApp');
+                $("#" + buttonId).addClass('SelectedWebApp');
+            }
+            else {
+                $('#applications_header BUTTON').attr('disabled', false);
+            }
+        }
+
+        $('#applications_header BUTTON').attr('disabled', true);
+        if (m_loadedWebAppIndex != undefined && WebApplications[m_loadedWebAppIndex].application != undefined && WebApplications[m_loadedWebAppIndex].application.unload != undefined) {
+            WebApplications[m_loadedWebAppIndex].application.unload(webappUnloaded);
+        } else {
+            webappUnloaded(true);
+        }
+    }
+
+    function webAppsDirLoaded(data) {
+        // Runs after all WebApplications/<WebAppDir>/Main.js are parsed, so WebApplications is populated by now.
+        var applications = data.availableApps;
+        var defaultApp = data.defaultApp;
+
+        function webAppsLoaded(ok, msg) {
+            var app = getLocationParam('app');
+            if (app != undefined) {
+                var index = parseInt(app);
+                if (isNaN(index)) {
+                    m_this.loadApp(app);
+                } else {
+                    webappBtnClicked(index, 'applications_header_appBtn_' + index, true);
+                }
+            } else if (defaultApp != undefined) {
+                m_this.loadApp(defaultApp);
+            }
+        }
+
+        function ApplicationLoadTask(index, application) {
+            var v_callback;
+            var v_index = index;
+            var v_directory = application.directory;
+            var v_params = application.params;
+            var v_name = application.name;
+            var v_icon = application.icon;
+            var v_color = application.color;
+            var v_hidden = application.hidden;
+
+            function mainJsFileImported(ok) {
+                if (ok) {
+                    var webApp = WebApplications[WebApplications.length - 1];
+                    if (v_name == undefined) {
+                        v_name = webApp.application.info().defaultName;
+                    }
+                    if (v_icon == undefined) {
+                        v_icon = webApp.application.info().defaultIcon;
+                    }
+                    webApp.name = v_name;
+                    if (v_params != undefined) {
+                        webApp.params = v_params;
+                    } else {
+                        webApp.params = {};
+                    }
+
+                    var buttonId = 'applications_header_appBtn_' + v_index;
+                    var buttonHtml = ''
+                    if (v_color != undefined) {
+                        buttonHtml = '<button index="' + v_index + '" id="' + buttonId + '" style="background-color:' + v_color + '; border-color:' + v_color + ';"><span><img src="' + v_icon + '"/>' + v_name + '</span></button>';
+                    } else {
+                        buttonHtml = '<button index="' + v_index + '" id="' + buttonId + '"><span><img src="' + v_icon + '"/>' + v_name + '</span></button>';
+                    }
+                    if (v_hidden && !(getLocationParam('developerMode') == "true")) {
+                        //$('#hiddenWebapps').append(buttonHtml);
+                    } else {
+                        $('#webapps').append(buttonHtml);
+                    }
+
+                    $("#" + buttonId).on('click', function() {
+                        webappBtnClicked(parseInt($(this).attr('index')), $(this).attr('id'), true);
+                    }).on('mouseup', function(e) {
+                        if (e.which == 2) {
+                            var url = 'Main.html?app=' + $(this).attr('index');
+                            var win = window.open(url, '_blank');
+                        }
+                    });
+                } else {
+                    alert('Failed to load application ' + v_name);
+                }
+
+                v_callback(true);
+            }
+
+            this.taskOperation = function(callback) {
+                v_callback = callback;
+                m_fileHandler.importJsFile(v_directory + '/Main.js', mainJsFileImported);
+            };
+        }
+
+        var importTasks = [];
+        for (var i = 0; i < applications.length; ++i) {
+            importTasks[i] = new ApplicationLoadTask(i, applications[i]);
+        }
+        var taskList = new SyncTaskList(importTasks, webAppsLoaded);
+        taskList.taskOperation();
+
+        // $('#webappToggleButton').click(function () {
+        //     $('#hiddenWebapps').toggleClass('hidden');
+        // });
+    }
+
+    function start() {
+        if (getLocationParam('hideRibbon') == 'true') {
+            $('#applications_header_container').addClass('hidden');
+        }
+
+        // load framework javascript and css files
+        new MultipleDirectoryListTask(
+            [
+                "WebApplicationFramework/Views",
+                "WebApplicationFramework/ViewModels"
+            ],
+            m_fileHandler
+        ).taskOperation(function(ok, resources) {
+            m_fileHandler.loadCssFiles(resources.cssfiles, "TSGuiFrameworkMain");
+            new JsImportTaskList(resources.jsfiles, m_fileHandler, function(ok) {
+                m_webAppModel.loadMainConfig(webAppsDirLoaded);
+            }).taskOperation();
+        });
+    }
+
+    var browser = browserCheck();
+    if ((browser[0].toLowerCase() == "firefox" && parseInt(browser[1].split(".")[0]) >= 38) || browser[0].toLowerCase() == "chrome") {
+        start();
+    } else {
+        var html = '' +
+        '<div id="UnsupportedBrowser">' +
+            '<p>This browser is not supported: ' + browser[0] + ' ' + browser[1] + '</p>' +
+            '<p>Please use at least Firefox 38 or Chrome</p>' +
+            '<button>Continue anyway...</button>' +
+        '</div>'
+        $("#TSGuiFrameworkMain").append(html);
+        $("#UnsupportedBrowser > button").on("click", function() {
+            $("#UnsupportedBrowser").remove();
+            start();
+        });
+    }
+});
+
+function WebAppBase() {
+    "use strict";
+    var m_loaded = false;
+    var m_imported = false;
+
+    this.unload = function(destroy) {
+        if (m_loaded) {
+            destroy();
+            m_loaded = false;
+        }
+    };
+
+    this.load = function(jsfiles, alwasyImportableJsFiles, start, fileHandler) {
+        if (m_imported) {
+            jsfiles = alwasyImportableJsFiles
+        } else {
+            jsfiles = jsfiles.concat(alwasyImportableJsFiles)
+        }
+
+        var taskList = new JsImportTaskList(jsfiles, fileHandler, function(ok, msg) {
+            if (ok) {
+                start(function() {
+                    $('#applications_header BUTTON').attr('disabled', false);
+                });
+                m_imported = true;
+                m_loaded = true;
+            } else {
+                alert('WebAppBase::load says task was not OK:' + JSON.stringify(msg, null, 4));
+            }
+        });
+        taskList.taskOperation();
+    };
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Res/DataTables_BasicStyles.css b/htdocs/WebApplicationFramework/Res/DataTables_BasicStyles.css
new file mode 100644
index 0000000..cad3e11
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/DataTables_BasicStyles.css
@@ -0,0 +1,137 @@
+

+table.dataTable tr td {

+    height: 10px;

+    padding: 0px 0px;

+    font-weight: normal !important;

+    font-family: "Arial";

+    /*font-size: 11px !important;	*/

+}

+

+table.dataTable th {

+    background-color: #66CBE5;

+    color: black;

+    font-weight: bold;

+    /*font-size: 14px;*/

+    text-align: left;

+}

+

+table.dataTable tbody tr:nth-child(odd) {

+    background-color: #D4F0F8;

+    color: black;

+}

+

+table.dataTable tbody tr:nth-child(even) {

+    background-color: #F2FBFD;

+    color: black;

+}

+

+table.dataTable tbody tr td:first-child {

+    font-weight: bold;

+}

+

+table.dataTable tbody tr:hover {

+    background-color: #0066b3;

+    color: white;

+}

+

+

+table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {

+  background-color: #D4F0F8 !important;

+}

+

+table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {

+  background-color: #D4F0F8 !important;

+}

+table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {

+  background-color: #D4F0F8 !important;

+}

+table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {

+  background-color: #66A19F !important;

+}

+table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {

+  background-color: #66A19F !important;

+}

+table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {

+  background-color: #66A19F !important;

+}

+table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {

+  background-color: #F2FBFD  !important;

+}

+table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {

+  background-color: #F2FBFD  !important;

+}

+table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {

+  background-color: #F2FBFD  !important;

+}

+table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {

+  background-color: #66A19F !important;

+}

+table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {

+  background-color: #66A19F !important;

+}

+table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {

+  background-color: #66A19F !important;

+}

+

+table.dataTable.hover tbody tr:hover.selected,

+table.dataTable.hover tbody tr.odd:hover.selected,

+table.dataTable.hover tbody tr.even:hover.selected, table.dataTable.display tbody tr:hover.selected,

+table.dataTable.display tbody tr.odd:hover.selected,

+table.dataTable.display tbody tr.even:hover.selected {

+  background-color: #0066b3 !important;

+}

+

+table.dataTable.hover tbody tr:hover,

+table.dataTable.hover tbody tr.odd:hover,

+table.dataTable.hover tbody tr.even:hover, table.dataTable.display tbody tr:hover,

+table.dataTable.display tbody tr.odd:hover,

+table.dataTable.display tbody tr.even:hover {

+  background-color: #0066b3 !important;

+}

+

+table.dataTable.display tbody tr:hover > .sorting_1,

+table.dataTable.display tbody tr.odd:hover > .sorting_1,

+table.dataTable.display tbody tr.even:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1,

+table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_1,

+table.dataTable.order-column.hover tbody tr.even:hover > .sorting_1 {

+  background-color: #0066b3 !important;

+}

+table.dataTable.display tbody tr:hover > .sorting_2,

+table.dataTable.display tbody tr.odd:hover > .sorting_2,

+table.dataTable.display tbody tr.even:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2,

+table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_2,

+table.dataTable.order-column.hover tbody tr.even:hover > .sorting_2 {

+  background-color: #0066b3 !important;

+}

+table.dataTable.display tbody tr:hover > .sorting_3,

+table.dataTable.display tbody tr.odd:hover > .sorting_3,

+table.dataTable.display tbody tr.even:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3,

+table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_3,

+table.dataTable.order-column.hover tbody tr.even:hover > .sorting_3 {

+  background-color: #0066b3 !important;

+}

+table.dataTable.display tbody tr:hover.selected > .sorting_1,

+table.dataTable.display tbody tr.odd:hover.selected > .sorting_1,

+table.dataTable.display tbody tr.even:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1,

+table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_1,

+table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_1 {

+  background-color: #0066b3 !important;

+}

+table.dataTable.display tbody tr:hover.selected > .sorting_2,

+table.dataTable.display tbody tr.odd:hover.selected > .sorting_2,

+table.dataTable.display tbody tr.even:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2,

+table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_2,

+table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_2 {

+  background-color: #0066b3 !important;

+}

+table.dataTable.display tbody tr:hover.selected > .sorting_3,

+table.dataTable.display tbody tr.odd:hover.selected > .sorting_3,

+table.dataTable.display tbody tr.even:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3,

+table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_3,

+table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_3 {

+  background-color: #0066b3 !important;

+}

+

+table.dataTable tbody tr.selected {

+  background-color: #66A19F !important;

+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Res/Main.css b/htdocs/WebApplicationFramework/Res/Main.css
new file mode 100644
index 0000000..6d9ce1d
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/Main.css
@@ -0,0 +1,123 @@
+html {
+    height: 100%;
+}
+
+body {
+    background-color: #EEEEEE;
+    height: calc(100% - 20px);
+    font-family: "Arial", "Helvetica", "Tahoma", "Geneva", "Verdana", sans-serif;
+    font-size:12px;
+    outline: none;
+}
+
+iframe {
+    border: none;
+}
+
+#TSGuiFrameworkMain {
+    height: 100%;
+}
+
+#UnsupportedBrowser {
+    width: 100%;
+    height: 100%;
+    text-align: center;
+    vertical-align: middle;
+}
+
+#UnsupportedBrowser > p {
+    font-size: 20px;
+}
+
+#UnsupportedBrowser > button {
+    font-size: 20px;
+}
+
+:focus {
+    outline: none;
+}
+
+button::-moz-focus-inner {
+    border: none;
+}
+
+.applications_header_class {
+    font-weight: bold;
+    font-family: "Arial";
+}
+
+.line {
+	clear: both;
+	width: 100%;
+	margin-top: 6px;
+	border-top: 1px solid #C4C4C3;
+	border-bottom: 1px solid #ffffff;
+	margin-bottom: 6px;
+}
+
+.tabs {
+    padding: 0px 0px !important;
+    height: 800px;
+}
+
+#eriHdr {
+	height: 30px;
+}
+
+#eriHdr IMG {
+	vertical-align: middle;
+	margin-left: 5px;
+	margin-right: 5px;
+}
+
+#webappToggle span {
+    text-align: center;
+    vertical-align: middle;
+}
+
+#webappToggle img {
+    height: 20px;
+    width: 20px;
+}
+
+#webapps, #webappToggle, #hiddenWebapps {
+	float: right;
+}
+
+#webapps BUTTON, #hiddenWebapps BUTTON, #webappToggleButton {
+    height: 30px;
+    color: #000;
+    border: 2px solid #c5c5c5;
+    background-color: #c5c5c5;
+    text-align: center;
+    text-decoration: none;
+    cursor:pointer;
+}
+
+#webapps BUTTON:disabled SPAN {
+    color: #777777;
+}
+
+#webapps BUTTON SPAN {
+	display: inline-block;
+}
+
+#webapps BUTTON:hover {
+    background-color: #999;
+    color: white;
+}
+
+#webapps BUTTON.SelectedWebApp, #hiddenWebapps BUTTON.SelectedWebApp {
+    background-color: #4CAF50;
+    color: white;
+}
+
+#webapps BUTTON IMG, #hiddenWebapps BUTTON IMG {
+	height: 16px;
+	vertical-align: middle;
+	margin-right: 5px;
+}
+
+.hidden {
+    display: none;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Res/arrowDown.png b/htdocs/WebApplicationFramework/Res/arrowDown.png
new file mode 100644
index 0000000..978971e
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/arrowDown.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/arrowUp.png b/htdocs/WebApplicationFramework/Res/arrowUp.png
new file mode 100644
index 0000000..da3b463
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/arrowUp.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/blackLED.png b/htdocs/WebApplicationFramework/Res/blackLED.png
new file mode 100644
index 0000000..bbe12c5
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/blackLED.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/blueLED.png b/htdocs/WebApplicationFramework/Res/blueLED.png
new file mode 100644
index 0000000..8ebcc09
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/blueLED.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/clear.png b/htdocs/WebApplicationFramework/Res/clear.png
new file mode 100644
index 0000000..c6377f0
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/clear.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/configure.png b/htdocs/WebApplicationFramework/Res/configure.png
new file mode 100644
index 0000000..c2fbc63
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/configure.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/d.png b/htdocs/WebApplicationFramework/Res/d.png
new file mode 100644
index 0000000..a8be6e3
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/d.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/edit_file.png b/htdocs/WebApplicationFramework/Res/edit_file.png
new file mode 100644
index 0000000..29b60c5
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/edit_file.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/ericsson-whitebg.png b/htdocs/WebApplicationFramework/Res/ericsson-whitebg.png
new file mode 100644
index 0000000..201dd10
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/ericsson-whitebg.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/ericsson.png b/htdocs/WebApplicationFramework/Res/ericsson.png
new file mode 100644
index 0000000..dc90961
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/ericsson.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/exit.png b/htdocs/WebApplicationFramework/Res/exit.png
new file mode 100644
index 0000000..4737107
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/exit.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/f.png b/htdocs/WebApplicationFramework/Res/f.png
new file mode 100644
index 0000000..3ff2334
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/f.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/favicon.ico b/htdocs/WebApplicationFramework/Res/favicon.ico
new file mode 100644
index 0000000..3923ec1
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/favicon.ico
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/folder.png b/htdocs/WebApplicationFramework/Res/folder.png
new file mode 100644
index 0000000..56c63ed
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/folder.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/folder_download.png b/htdocs/WebApplicationFramework/Res/folder_download.png
new file mode 100644
index 0000000..51fd969
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/folder_download.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/gear.png b/htdocs/WebApplicationFramework/Res/gear.png
new file mode 100644
index 0000000..19ae4d9
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/gear.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/greenLED.png b/htdocs/WebApplicationFramework/Res/greenLED.png
new file mode 100644
index 0000000..eec36e1
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/greenLED.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/grip.png b/htdocs/WebApplicationFramework/Res/grip.png
new file mode 100644
index 0000000..439fc95
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/grip.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/grip_gray.png b/htdocs/WebApplicationFramework/Res/grip_gray.png
new file mode 100644
index 0000000..7e305c6
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/grip_gray.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/grip_white.png b/htdocs/WebApplicationFramework/Res/grip_white.png
new file mode 100644
index 0000000..4446106
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/grip_white.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/help.png b/htdocs/WebApplicationFramework/Res/help.png
new file mode 100644
index 0000000..abae95c
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/help.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/home16.png b/htdocs/WebApplicationFramework/Res/home16.png
new file mode 100644
index 0000000..a48a296
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/home16.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/kill.png b/htdocs/WebApplicationFramework/Res/kill.png
new file mode 100644
index 0000000..100e40e
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/kill.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/ld.png b/htdocs/WebApplicationFramework/Res/ld.png
new file mode 100644
index 0000000..b429d9c
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/ld.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/lf.png b/htdocs/WebApplicationFramework/Res/lf.png
new file mode 100644
index 0000000..1a2811a
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/lf.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/machine.png b/htdocs/WebApplicationFramework/Res/machine.png
new file mode 100644
index 0000000..33d83b9
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/machine.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/new_file.png b/htdocs/WebApplicationFramework/Res/new_file.png
new file mode 100644
index 0000000..f1f86f6
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/new_file.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/open_gui.png b/htdocs/WebApplicationFramework/Res/open_gui.png
new file mode 100644
index 0000000..9bff7f5
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/open_gui.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/pause.png b/htdocs/WebApplicationFramework/Res/pause.png
new file mode 100644
index 0000000..ddc74af
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/pause.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/print.png b/htdocs/WebApplicationFramework/Res/print.png
new file mode 100644
index 0000000..cd942b4
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/print.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/redLED.png b/htdocs/WebApplicationFramework/Res/redLED.png
new file mode 100644
index 0000000..1bc6197
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/redLED.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/resettest.png b/htdocs/WebApplicationFramework/Res/resettest.png
new file mode 100644
index 0000000..97dda71
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/resettest.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/save.png b/htdocs/WebApplicationFramework/Res/save.png
new file mode 100644
index 0000000..b2d058d
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/save.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/sort_asc.png b/htdocs/WebApplicationFramework/Res/sort_asc.png
new file mode 100644
index 0000000..e1ba61a
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/sort_asc.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/sort_both.png b/htdocs/WebApplicationFramework/Res/sort_both.png
new file mode 100644
index 0000000..af5bc7c
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/sort_both.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/sort_desc.png b/htdocs/WebApplicationFramework/Res/sort_desc.png
new file mode 100644
index 0000000..0e156de
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/sort_desc.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/start.png b/htdocs/WebApplicationFramework/Res/start.png
new file mode 100644
index 0000000..0d43e7c
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/start.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/start_green.png b/htdocs/WebApplicationFramework/Res/start_green.png
new file mode 100644
index 0000000..8aa8f55
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/start_green.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/starttest-whitebg.png b/htdocs/WebApplicationFramework/Res/starttest-whitebg.png
new file mode 100644
index 0000000..c415e54
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/starttest-whitebg.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/starttest.png b/htdocs/WebApplicationFramework/Res/starttest.png
new file mode 100644
index 0000000..0c6ac61
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/starttest.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/stoptest.png b/htdocs/WebApplicationFramework/Res/stoptest.png
new file mode 100644
index 0000000..26551b4
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/stoptest.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/switchOff.png b/htdocs/WebApplicationFramework/Res/switchOff.png
new file mode 100644
index 0000000..cf04f73
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/switchOff.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/switchOff_disabled.png b/htdocs/WebApplicationFramework/Res/switchOff_disabled.png
new file mode 100644
index 0000000..0476e49
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/switchOff_disabled.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/switchOn.png b/htdocs/WebApplicationFramework/Res/switchOn.png
new file mode 100644
index 0000000..1213778
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/switchOn.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/switchOn_disabled.png b/htdocs/WebApplicationFramework/Res/switchOn_disabled.png
new file mode 100644
index 0000000..bd22eae
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/switchOn_disabled.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/terminate-fancy.png b/htdocs/WebApplicationFramework/Res/terminate-fancy.png
new file mode 100644
index 0000000..e1c1eae
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/terminate-fancy.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/terminate-orig-small.png b/htdocs/WebApplicationFramework/Res/terminate-orig-small.png
new file mode 100644
index 0000000..8ba9699
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/terminate-orig-small.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/terminate.png b/htdocs/WebApplicationFramework/Res/terminate.png
new file mode 100644
index 0000000..ac00a09
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/terminate.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/waiting.gif b/htdocs/WebApplicationFramework/Res/waiting.gif
new file mode 100644
index 0000000..e2f01c2
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/waiting.gif
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Res/yellowLED.png b/htdocs/WebApplicationFramework/Res/yellowLED.png
new file mode 100644
index 0000000..c418cb9
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Res/yellowLED.png
Binary files differ
diff --git a/htdocs/WebApplicationFramework/Setup_Model.js b/htdocs/WebApplicationFramework/Setup_Model.js
new file mode 100644
index 0000000..7ffa8bc
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Setup_Model.js
@@ -0,0 +1,391 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CSetup_Model(p_fileHandler) {

+    "use strict";

+    

+    var v_setupDirectory = "";

+    var v_fileHandler = p_fileHandler;

+    var v_setup = {};

+

+    this.setSetupDirectory = function(directory) {

+        v_setupDirectory = directory;

+    };

+

+    this.newSetup = function() {

+        v_setup.request = new JsonLoader(undefined, v_fileHandler, []);

+        v_setup.viewmodels = new JsonLoader(undefined, v_fileHandler, []);

+        v_setup.views = new JsonLoader(undefined, v_fileHandler, []);

+        v_setup.imports = new JsonLoader(undefined, v_fileHandler, []);

+        v_setup.desktop = new JsonLoader(undefined, v_fileHandler, {});

+        v_setup.html = new FileLoader(undefined, v_fileHandler, '<div id="div_id"></div>');

+        v_setup.css = new FileLoader(undefined, v_fileHandler);

+        v_setup.name = undefined;

+        return v_setup;

+    };

+

+    this.loadSetup = function(setupName, callback, doNotResolveImports, setupParams) {

+        function importsResolved(ok) {

+            callback(ok, v_setup, setupName)

+        }

+

+        function setupLoaded(ok, setup, setupName) {

+            if (doNotResolveImports == undefined || doNotResolveImports == false) {

+                resolveImports(importsResolved)

+            } else {

+                callback(ok, setup, setupName);

+            }

+        }

+        loadSetupFromFiles(setupName, v_setup, setupParams, setupLoaded);

+    };

+

+    function loadSetupFromFiles(setupName, setup, setupParams, callback) {

+        var setupLocation = v_setupDirectory + "/" + setupName;

+        function jsonImported(ok, data) {

+            if (setupParams != undefined && Object.keys(setupParams).length > 0) {

+                replaceSetupParams(setup);

+            }

+            if (callback != undefined) {

+                callback(ok, setup, setupName);

+            }

+        }

+

+        setup.request = new JsonLoader(setupLocation + "/Request.json", v_fileHandler, []);

+        setup.viewmodels = new JsonLoader(setupLocation + "/ViewModelInstances.json", v_fileHandler, []);

+        setup.views = new JsonLoader(setupLocation + "/ViewInstances.json", v_fileHandler, []);

+        setup.imports = new JsonLoader(setupLocation + "/Imports.json", v_fileHandler, []);

+        setup.desktop = new JsonLoader(setupLocation + "/Desktop.json", v_fileHandler, {});

+        setup.html = new FileLoader(setupLocation + "/Setup.html", v_fileHandler);

+        setup.css = new FileLoader(setupLocation + "/Setup.css", v_fileHandler);

+        setup.name = setupName;

+        setup.setupParams = setupParams;

+

+        var taskList = new TaskList([setup.request, setup.viewmodels, setup.views, setup.imports, setup.desktop, setup.html, setup.css], jsonImported);

+        taskList.taskOperation();

+    }

+

+    this.getSetup = function() {

+        return v_setup;

+    };

+

+    this.saveSetup = function(callback) {

+        var taskList = new TaskList([

+            new JsonSaveTask(v_setup.request, undefined),

+            new JsonSaveTask(v_setup.viewmodels, undefined),

+            new JsonSaveTask(v_setup.views, undefined),

+            new JsonSaveTask(v_setup.imports, undefined),

+            new JsonSaveTask(v_setup.desktop, undefined),

+            new FileSaveTask(v_setup.html, undefined, undefined),

+            new FileSaveTask(v_setup.css, undefined, undefined),

+        ], callback);

+        taskList.taskOperation();

+    };

+

+    this.saveSetupAs = function(setupName, callback) {

+        v_setup.name = setupName;

+        var directory = v_setupDirectory + "/" + setupName;

+

+        function directoryCreated(success) {

+            if (!success) {

+                callback(false);

+                return;

+            }

+

+            var taskList = new TaskList([

+                new JsonSaveTask(v_setup.request, directory + "/Request.json"),

+                new JsonSaveTask(v_setup.viewmodels, directory + "/ViewModelInstances.json"),

+                new JsonSaveTask(v_setup.views, directory + "/ViewInstances.json"),

+                new JsonSaveTask(v_setup.imports, directory + "/Imports.json"),

+                new JsonSaveTask(v_setup.desktop, directory + "/Desktop.json"),

+                new FileSaveTask(v_setup.html, undefined, directory + "/Setup.html"),

+                new FileSaveTask(v_setup.css, undefined, directory + "/Setup.css"),

+            ], callback);

+            taskList.taskOperation();

+        }

+

+        function gotExistance(exists) {

+            if (exists) {

+                directoryCreated(true);

+            } else {

+                v_fileHandler.createDirectory(directory, directoryCreated);

+            }

+        }

+

+        this.setupExists(setupName, gotExistance);

+    };

+

+    this.deleteSetup = function(p_setupName, callback) {

+        var setupName = v_setupDirectory + "/" + p_setupName;

+        v_fileHandler.delDirectory(setupName, callback);

+    };

+

+    this.setupExists = function(p_setupName, callback) {

+        var setupLoaction = v_setupDirectory + "/" + p_setupName;

+        function setupsListed(setupDirs) {

+            for (var i = 0; i < setupDirs.length; ++i) {

+                if (setupLoaction === setupDirs[i].fileName) {

+                    callback(true);

+                    return;

+                }

+            }

+            callback(false);

+        }

+

+        listSetupDirs(setupsListed);

+    };

+

+    this.listSetups = function(a_callback) {

+        var callback = a_callback;

+        function setupsDirectoryLoaded(a_directories) {

+            var result = [];

+            for (var i = 0; i < a_directories.length; ++i) {

+                result.push(a_directories[i].fileName.substring(a_directories[i].fileName.lastIndexOf("/") + 1));

+            }

+            result.sort();

+            callback(result);

+        }

+        listSetupDirs(setupsDirectoryLoaded);

+    };

+

+    this.globalSetupSearch = function(input, choices, p_callback) {

+        input = input.toLowerCase();

+        var indexes = [];

+        var tasks = [];

+

+        function SearchTask(fileName, index) {

+            var v_fileName = fileName;

+            var v_index = index;

+

+            this.taskOperation = function(callback) {

+                v_fileHandler.loadFile(v_fileName, function(ok, data) {

+                    if (data.toLowerCase().indexOf(input) != -1 && indexes.indexOf(v_index) == -1) {

+                        indexes.push(v_index);

+                    }

+                    callback(true);

+                });

+            }

+        }

+

+        function searchComplete() {

+            p_callback(indexes);

+        }

+

+        for (var i = 0; i < choices.length; ++i) {

+            tasks.push(new SearchTask(v_setupDirectory + "/" + choices[i].value + "/Request.json", i));

+            tasks.push(new SearchTask(v_setupDirectory + "/" + choices[i].value + "/ViewModelInstances.json", i));

+            tasks.push(new SearchTask(v_setupDirectory + "/" + choices[i].value + "/ViewInstances.json", i));

+            tasks.push(new SearchTask(v_setupDirectory + "/" + choices[i].value + "/Imports.json", i));

+            tasks.push(new SearchTask(v_setupDirectory + "/" + choices[i].value + "/Setup.html", i));

+            tasks.push(new SearchTask(v_setupDirectory + "/" + choices[i].value + "/Setup.css", i));

+        }

+

+        var taskList = new TaskList(tasks, searchComplete);

+        taskList.taskOperation();

+    };

+

+    this.setAPI = function(a_api) {

+        v_fileHandler = a_api;

+    };

+

+    function replaceSetupParams(setup) {

+        var setupParts = ["request", "viewmodels", "views", "imports"];

+        for (var i = 0; i < setupParts.length; ++i) {

+            var data = JSON.stringify(setup[setupParts[i]].getData());

+            for (var key in setup.setupParams) {

+                data = data.replace(key, setup.setupParams[key]);

+            }

+            setup[setupParts[i]].setData(JSON.parse(data));

+        }

+

+        setupParts = ["html", "css"];

+        for (var i = 0; i < setupParts.length; ++i) {

+            var data = setup[setupParts[i]].getData();

+            for (var key in setup.setupParams) {

+                data = data.replace(key, setup.setupParams[key]);

+            }

+            setup[setupParts[i]].setData(data);

+        }

+    }

+

+    function listSetupDirs(a_callback) {

+        v_fileHandler.getDirectory(v_setupDirectory, a_callback);

+    }

+

+    function resolveImports(a_callback) {

+        var importResolver = new CImportResolver(v_setup, loadSetupFromFiles);

+        importResolver.resolveImports(a_callback);

+    }

+}

+

+function CImportResolver(a_setup, a_setupLoaderFunction) {

+    var v_setup = a_setup;

+

+    var loadSetupFromFiles = a_setupLoaderFunction;

+

+    this.resolveImports = function(a_callback) {

+        mergeSetups(v_setup.imports.getData(), [v_setup.name], a_callback);

+    };

+

+    function mergeSetups(importList, importedSetupsPath, callback) {

+        if (importList.length == 0) {

+            callback(true);

+        } else {

+            var mergeTasks = [];

+            for (var i = 0; i < importList.length; ++i) {

+                if (importedSetupsPath.indexOf(importList[i].setupName) != -1) {

+                    alert("Circular importation of setups detected: " + importedSetupsPath + " " + importList[i].setupName);

+                } else {

+                    var viewIdPrefixes = "i" + importedSetupsPath.length + "_" + i + "_";

+                    mergeTasks.push(new MergeTask(importList[i].setupName, importedSetupsPath, viewIdPrefixes, importList[i].parentID, importList[i].requetsPath, importList[i].setupParams));

+                }

+            }

+            var taskList = new TaskList(mergeTasks, callback);

+            taskList.taskOperation();

+        }

+    }

+

+    function MergeTask(setupName, importedSetupsPath, viewIdPrefixes, parentID, requetsPath, setupParams) {

+        var name = setupName;

+        var path = mcopy(importedSetupsPath);

+        path.push(name);

+        var params = setupParams;

+        var prefix = viewIdPrefixes;

+        var idToCreate = parentID;

+

+        this.taskOperation = function(callback) {

+            function setupLoaded(ok, setup, setupName) {

+                if (ok) {

+                    mergeSetup(setup, prefix, idToCreate, requetsPath);

+                    mergeSetups(setup.imports.getData(), path, callback);

+                } else {

+                    alert("Failed to load imported setup: " + name);

+                    callback(true);

+                }

+            }

+

+            loadSetupFromFiles(name, {}, params, setupLoaded);

+        }

+    }

+

+    function mergeSetup(setup, viewIdPrefixes, parentID, requetsPath) {

+        var viewModelIndexOffset = v_setup.viewmodels.getData().length;

+        var requestPathPrefix = [];

+        if (requetsPath != undefined) {

+            requestPathPrefix = requetsPath;

+        }

+        var requestPathOffset = mergeRequest(setup.request.getData(), requestPathPrefix);

+        mergeViewmodels(setup.viewmodels.getData(), requestPathPrefix, requestPathOffset);

+        updateImportRequestPaths(setup.imports.getData(), requestPathPrefix, requestPathOffset);

+        addPrefixToIds(setup, viewIdPrefixes);

+        addViewForHtml(setup, parentID);

+        mergeViews(setup.views.getData(), viewModelIndexOffset);

+        mergeCss(setup.css.getData());

+    }

+

+    function mergeRequest(request, path) {

+        var requestsToExpand = v_setup.request.getData();

+        for (var i = 0; i < path.length; ++i) {

+            if (requestsToExpand[path[i]].getData.children == undefined) {

+                requestsToExpand[path[i]].getData.children = [];

+            }

+            requestsToExpand = requestsToExpand[path[i]].getData.children;

+        }

+        var requestPathOffset = requestsToExpand.length;

+

+        for (var i = 0; i < request.length; ++i) {

+            requestsToExpand.push(request[i]);

+        }

+

+        return requestPathOffset;

+    }

+

+    function mergeViewmodels(viewmodels, prefix, offset) {

+        var origViewmodels = v_setup.viewmodels.getData();

+        for (var i = 0; i < viewmodels.length; ++i) {

+            for (var j = 0; j < viewmodels[i].dataPathList.length; ++j) {

+                updatePath(viewmodels[i].dataPathList[j], prefix, offset);

+            }

+            for (var j = 0; j < viewmodels[i].selectionToControlPathList.length; ++j) {

+                updatePath(viewmodels[i].selectionToControlPathList[j], prefix, offset);

+            }

+            origViewmodels.push(viewmodels[i]);

+        }

+    }

+

+    function updatePath(path, prefix, offset) {

+        path[0] += offset;

+        for (var i = prefix.length - 1; i >= 0; --i) {

+            path.unshift(prefix[i]);

+        }

+    }

+

+    function updateImportRequestPaths(imports, prefix, offset) {

+        for (var i = 0; i < imports.length; ++i) {

+            if (imports[i].requestPath != undefined) {

+                updatePath(imports[i].requestPath, prefix, offset);

+            }

+        }

+    }

+

+    function addPrefixToIds(setup, viewIdPrefixes) {

+        var views = setup.views.getData();

+        var imports = setup.imports.getData();

+        var html = setup.html.getData();

+

+        for (var i = 0; i < views.length; ++i) {

+            views[i].parentID = viewIdPrefixes + views[i].parentID;

+            for (var j = 0; j < views[i].idsCreating.length; ++j) {

+                views[i].idsCreating[j] = viewIdPrefixes + views[i].idsCreating[j];

+            }

+        }

+

+        for (var i = 0; i < imports.length; ++i) {

+            imports[i].parentID = viewIdPrefixes + imports[i].parentID;

+        }

+

+        html = html.replace(/id="([^"]+)"/gm, function(matchedString, matchedPart, index) {

+            return 'id="' + viewIdPrefixes + matchedPart + '"';

+        });

+        setup.html.setData(html);

+    }

+

+    function addViewForHtml(setup, parentID) {

+        var html = setup.html.getData();

+        var idsCreating = [];

+

+        var pattern = new RegExp(/id="([^"]+)"/gm);

+        var str = html;

+        var match = pattern.exec(str);

+        while (match != undefined) {

+            idsCreating.push(match[1]);

+            match = pattern.exec(str);

+        }

+

+        var viewDescriptor = {

+            "class": "CView_Div",

+            "viewModelIndexes": [],

+            "parentID": parentID,

+            "idsCreating": idsCreating,

+            "customData": {

+                "text": html

+            }

+        }

+        setup.views.getData().unshift(viewDescriptor);

+    }

+

+    function mergeViews(views, offset) {

+        var origViews = v_setup.views.getData();

+        for (var i = 0; i < views.length; ++i) {

+            for (var j = 0; j < views[i].viewModelIndexes.length; ++j) {

+                views[i].viewModelIndexes[j] += offset;

+            }

+            origViews.push(views[i]);

+        }

+    }

+

+    function mergeCss(css) {

+        v_setup.css.setData(v_setup.css.getData() + "\n" + css);

+    }

+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/ViewModels/ViewModel_FileSelector.js b/htdocs/WebApplicationFramework/ViewModels/ViewModel_FileSelector.js
new file mode 100644
index 0000000..f11bd31
--- /dev/null
+++ b/htdocs/WebApplicationFramework/ViewModels/ViewModel_FileSelector.js
@@ -0,0 +1,408 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_FileSelector(p_viewmodel, p_options) {
+    "use strict";
+
+    var v_fileHandler = p_viewmodel.getFileHandler();
+    var v_binder;
+    var v_options = p_options;
+    
+    var currentDir;
+    var currentDirContents;
+    var selection;
+    
+    var undoStack = [];
+    var redoStack = [];
+    var currentFilter;
+    
+    var v_this = this;
+    
+    if (v_options == undefined) {
+        v_options = {};
+    }
+    
+    if (v_options["targetType"] == undefined) {
+        v_options["targetType"] = "file";
+    }
+    
+    if (v_options["fileTypeList"] == undefined || v_options["fileTypeList"].length == 0) {
+        v_options["fileTypeList"] = ["*.*", "*.js", "*.html", "*.css", "*.cfg"];
+    }
+    
+    if (v_options["defaultDir"] == undefined) {
+        v_options["defaultDir"] = "/";
+    }
+    
+    if (v_options["multipleSelection"] == undefined) {
+        v_options["multipleSelection"] = false;
+    }
+    
+    currentDir = v_options["defaultDir"];
+    currentFilter = v_options["fileTypeList"][0];
+    
+    /** public functions - interface for parent */ 
+
+    this.setSelectionToControl = function() {};
+    this.setReponseDataPath = function() {};
+    this.setBinder = function(p_binder) {
+        v_binder = p_binder;
+    };
+    
+    /** public functions - interface for views */ 
+    
+    this.filesSelected = function() {
+        alert(JSON.stringify(selection, null, 2));
+    };
+    
+    this.fileSelectionCanceled = function() {
+        alert("Selection canceled");
+    };
+
+    this.getCurrentDirElements = function() {
+        var content = [{
+            "type" : "-d",
+            "name" : "..",
+            "displayName" : "..",
+            "size" : 0,
+            "timestamp" : 0,
+            "id" : -1
+        }];
+        
+        var filter = currentFilter;
+        filter = filter.replace(".*", "");
+        filter = filter.replace("*", "");
+        
+        for (var i = 0; i < currentDirContents.length; ++i) {
+            var name = currentDirContents[i]["fileName"];
+            if (currentDirContents[i]["contentType"].endsWith("d") || name.endsWith(filter)) {
+                var displayName = getLastName(name);
+                content.push({
+                    "type" : currentDirContents[i]["contentType"],
+                    "name" : name,
+                    "displayName" : displayName,
+                    "size" : currentDirContents[i]["size"],
+                    "timestamp" : currentDirContents[i]["timestamp"],
+                    "id" : i
+                });
+            }
+        }
+        
+        return content;
+    };
+    
+    this.getCurrentDir = function() {
+        return currentDir;
+    };
+    
+    this.action = function(id, name, type, refresh) {
+        if (type == "doubleclick") {
+            if (id == -1 || currentDirContents[id]["contentType"] == "-d" || currentDirContents[id]["contentType"] == "ld") {
+                changeDir(name, refresh);
+            } else {
+                select(currentDirContents[id], name, false, refresh);
+            }
+        } else if (type == "click" && id != -1) {
+            select(currentDirContents[id], name, false, refresh);
+        } else if (type == "ctrlclick" && id != -1) {
+            select(currentDirContents[id], name, true, refresh);
+        }
+    };
+    
+
+    
+    this.back = function(refresh) {
+        if (!v_this.allowBack()) {
+            return;
+        }
+        
+        redoStack.push(currentDir);
+        currentDir = undoStack.pop();
+        
+        v_fileHandler.getDirectory(currentDir, function(content) {
+            currentDirContents = content;
+            selection = [];
+            refresh(true);
+        });
+    };
+    
+    this.forward = function(refresh) {
+        if (!v_this.allowForward()) {
+            return;
+        }
+        
+        undoStack.push(currentDir);
+        currentDir = redoStack.pop();
+        
+        v_fileHandler.getDirectory(currentDir, function(content) {
+            currentDirContents = content;
+            selection = [];
+            refresh(true);
+        });
+    }
+    
+    this.allowBack = function() {
+        return undoStack.length != 0;
+    };
+    
+    this.allowForward = function() {
+        return redoStack.length != 0;
+    };
+    
+    this.home = function(refresh) {
+        undoStack.push(currentDir);
+        redoStack = [];
+        currentDir = v_options["defaultDir"];
+        
+        v_fileHandler.getDirectory(currentDir, function(content) {
+            currentDirContents = content;
+            selection = [];
+            refresh(true);
+        });
+    };
+    
+    this.createDirectory = function(name, refresh) {
+        var path;
+        if (currentDir[currentDir.length - 1] == "/") {
+            path = currentDir + name;
+        } else {
+            path = currentDir + "/" + name;
+        }
+        
+        v_fileHandler.createDirectory(path, function(ok) {
+            if (ok) {
+                v_fileHandler.getDirectory(currentDir, function(content) {
+                    currentDirContents = content;
+                    selection = [];
+                    refresh(true);
+                });
+            } else {
+                alert("Error creating directory: " + path);
+            }
+        });
+    };
+
+    this.getSelection = function() {
+        return selection;
+    };
+    
+    this.setSelectionManually = function(name) {
+        var path;
+        if (currentDir[currentDir.length - 1] == "/") {
+            path = currentDir + name;
+        } else {
+            path = currentDir + "/" + name;
+        }
+        
+        var obj = {
+            "text": name,
+            "value" : path
+        }
+        
+        selection = [obj];
+    };
+    
+    this.getFileTypeList = function() {
+        var filters = v_options["fileTypeList"];
+        var list = [];
+        for (var i = 0; i < filters.length; ++i) {
+            list.push({
+                "value": filters[i],
+                "text": filters[i]
+            })
+        }
+        
+        return list;
+    }
+    
+    this.setFilter = function(text, refresh) {
+        currentFilter = text;
+        selection = [];
+        refresh(true);
+    };
+    
+    this.exists = function(path, callback) {
+        if (path.length > 1 && path[path.length - 1] == "/") {
+            path = path.substr(0, path.length - 1);
+        }
+        var name = getLastName(path);
+        if (name.length == 0 || name == "..") {
+            callback(true);
+        } else {
+            path = path.substr(0, path.length - name.length);
+            v_fileHandler.getDirectory(path, function(content) {
+                var found = false;
+                for (var i = 0; i < content.length; ++i) {
+                    if (content[i]["fileName"].endsWith(name)) {
+                        found = true;
+                        break;
+                    }
+                }
+                callback(found);
+            });
+        }
+    }
+    
+    this.loadFile = function(url, callback) {
+        return v_fileHandler.loadFile(url, callback);
+    };
+    
+    /** private functions */
+    
+    function changeDir(name, refresh) {
+        undoStack.push(currentDir);
+        redoStack = [];
+        
+        if (name == "..") {
+            if (currentDir != "/" && getLastName(currentDir) != "..") {
+                currentDir = currentDir.substr(0, currentDir.lastIndexOf("/"));
+                if (currentDir.length == 0 || currentDir[currentDir.length -1] == ".") {
+                    currentDir += "/";
+                }
+            } else {
+                if (currentDir == "/") {
+                    currentDir = ".." + currentDir;
+                } else {
+                    currentDir = "../" + currentDir;
+                }
+            }
+        } else {
+            if (currentDir[currentDir.length - 1] == "/") {
+                currentDir += name.substr(name.lastIndexOf("/") + 1);
+            } else {
+                currentDir += "/" + name.substr(name.lastIndexOf("/") + 1);
+            }
+        }
+        
+        v_fileHandler.getDirectory(currentDir, function(content) {
+            currentDirContents = content;
+            selection = [];
+            refresh(true);
+        });
+    }
+    
+    function getLastName(dir) {
+        var dirs = dir.split("/");
+        if (dir[dir.length - 1] == "/") {
+            return dirs[dirs.length - 2];
+        } else {
+            return dirs[dirs.length - 1];
+        }
+    }
+    
+    function select(content, name, multiple, refresh) {
+        if (name == "..") {
+            return;
+        }
+        
+        var targetType = v_options["targetType"];
+        var multipleSelectionAllowed = v_options["multipleSelection"];
+        
+        var selectionObject = getSelectionObject(content);
+        
+        if (
+            (targetType == "file" && (content["contentType"] == "-f" || content["contentType"] == "lf")) ||
+            (targetType == "dir" && (content["contentType"] == "-d" || content["contentType"] == "ld"))
+        ) {
+            if (multiple && multipleSelectionAllowed) {
+                multipleSelection(selectionObject, refresh);
+            } else {
+                singleSelection(selectionObject, refresh);
+            }
+        } else if (!multiple) {
+            selection = [];
+            refresh();
+        }
+    }
+    
+    function getSelectionObject(content) {
+        var value = content["fileName"];
+        var text = getLastName(value);
+        return {
+            "text" : text,
+            "value" : value
+        };
+    }
+    
+    function singleSelection(selectionObject, refresh) {
+        selection = [selectionObject];
+        refresh();
+    }
+    
+    function multipleSelection(selectionObject, refresh) {
+        var found = -1;
+        for (var i = 0; i < selection.length; ++i) {
+            if (selection[i].value == selectionObject.value) {
+                found = i;
+                break;
+            }
+        }
+        if (found != -1) {
+            selection.splice(i, 1);
+        } else {
+            selection.push(selectionObject);
+        }
+        refresh();
+    }
+}
+
+CViewModel_FileSelector.getHelp = function() {
+    return "A file selector viewmodel. Override its filesSelected and fileSelectionCanceled functions to create something useful.";
+};
+
+CViewModel_FileSelector.providesInterface = function() {
+    return ["filesSelected", "fileSelectionCanceled", "getCurrentDirElements", "getCurrentDir", "action",
+        "back", "forward", "allowBack", "allowForward", "home",
+        "createDirectory", "getSelection", "setSelectionManually", "getFileTypeList", "setFilter", "exists"];
+};
+
+CViewModel_FileSelector.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_FileSelector",
+        "type": "object",
+        "properties": {
+            "targetType": {
+                "description": "The type of selection",
+                "type": "string",
+                "enum": ["file", "dir"]
+            },
+            "fileTypeList": {
+                "description": "The file types that can be used to filter the shown results.",
+                "type": "array",
+                "format": "table",
+                "items": {
+                    "type": "string",
+                    "title": "file type",
+                    "default": "*.*",
+                    "pattern": "\\*\\.[A-Za-z0-9*]+$"
+                },
+                "uniqueItems": true,
+                "default": ["*.*"]
+            },
+            "defaultDir": {
+                "description": "The default directory that will first appear and that can be navigated to with the home button.",
+                "type": "string",
+                "default": "/"
+            },
+            "multipleSelection": {
+                "description": "Whether we allow multiple selection (default false).",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            }
+        },
+        "additionalProperties": false
+    };
+};
+
+CViewModel_FileSelector.expectsConnection = function() {
+    return {
+        "dataConnections": [],
+        "selectionConnections": []
+    };
+};
+
+//# sourceURL=WebApplicationFramework\ViewModels\FileSelector_ViewModel.js
diff --git a/htdocs/WebApplicationFramework/Views/View_Aligner.css b/htdocs/WebApplicationFramework/Views/View_Aligner.css
new file mode 100644
index 0000000..9f426c8
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Aligner.css
@@ -0,0 +1,41 @@
+.Aligner {
+    background-color: #f1f1f1;
+    height: 100%;
+    width: 100%;
+    vertical-align:top;
+    white-space: nowrap;
+    overflow: hidden;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+}
+
+.Aligner_Vertical_Content {
+    vertical-align:top;
+    display: block;
+    width: 100%;
+    overflow: hidden;
+    white-space: nowrap;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+}
+
+.Aligner_Horizontal_Content {
+    vertical-align:top;
+    display: inline-block;
+    height: 100%;
+    overflow: hidden;
+    white-space: nowrap;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+}
+
+.Aligner .ui-resizable-e {
+    right: 0px;
+}
+
+.Aligner .ui-resizable-handle {
+    width: 10px;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Aligner.js b/htdocs/WebApplicationFramework/Views/View_Aligner.js
new file mode 100644
index 0000000..8447bc9
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Aligner.js
@@ -0,0 +1,243 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_Aligner(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+
+    /** constructor */
+
+    var v_mainId = p_mainId;
+    var v_parentId = p_parentId;
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_Aligner)[0];
+    var v_conditionViewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_Aligner)[1];
+    var v_customData = p_data;
+
+    var v_subTotalSize;
+
+    var v_this = this;
+
+    /** public functions */
+
+    this.applicationCreated = function() {
+        var orientation = getOrientation();
+        if (!v_customData.existing) {
+            $("#" + v_parentId).append(getHtml(orientation));
+        }
+        setupCallbacks(orientation);
+    };
+
+    this.refresh = function() {
+        ViewUtils.checkVisibility(v_conditionViewmodel, v_mainId);
+    };
+
+    /** private functions */
+
+    function getOrientation() {
+        if (v_customData.orientation != undefined && v_customData.orientation.toLowerCase() == "vertical") {
+            return "Vertical";
+        } else {
+            return "Horizontal";
+        }
+    }
+
+    function getHtml(orientation) {
+        var html = '<div class="Aligner" id="' + v_mainId + '">';
+        var lengths = getLengths();
+        for (var i = 0; i < v_customData.idsCreating.length; ++i) {
+            html += getHtmlOfContent(i, orientation, lengths);
+        }
+        html += '</div>';
+        return html;
+    }
+
+    function getHtmlOfContent(contentIndex, orientation, lengths) {
+        var html = '';
+        html += '<div id="' + v_customData.idsCreating[contentIndex] + '" class="Aligner_' + orientation + '_Content"';
+        if (orientation == "Vertical" && lengths[contentIndex] != "") {
+            html += ' style="height: ' + lengths[contentIndex] + ';"';
+        } else if (lengths[contentIndex] != "") {
+            html += ' style="width: ' + lengths[contentIndex] + ';"';
+        }
+        html += '></div>';
+        return html;
+    }
+
+    /** protected functions */
+
+    this.getLenghtsFromViewmodel = function() {
+        if (v_viewmodel != undefined && v_viewmodel.getChildSizes != undefined) {
+            return v_viewmodel.getChildSizes(v_customData.idsCreating);;
+        } else {
+            return undefined;
+        }
+    };
+
+    /** private functions */
+
+    function getLengths() {
+        var lengths;
+        if (v_customData.flexCalculation == true || v_customData.resizable == true) {
+            lengths = v_this.getLenghtsFromViewmodel();
+            if (lengths == undefined) {
+                lengths = [];
+                var unitPercent = (100 / v_customData.idsCreating.length) + "%";
+                for (var i = 0; i < v_customData.idsCreating.length; ++i) {
+                    lengths.push(unitPercent);
+                }
+            }
+            return lengths;
+        } else {
+            lengths = [];
+            for (var i = 0; i < v_customData.idsCreating.length; ++i) {
+                lengths.push("");
+            }
+
+        }
+        return lengths;
+    };
+
+    function setupCallbacks(orientation) {
+        if (v_customData.resizable == true) {
+            var resizables = $("#" + p_mainId + " > div");
+            var options;
+            var cssToSet;
+            if (orientation == "Vertical") {
+                cssToSet = "height";
+                options = {
+                    handles: "s",
+                    start: function(event, ui){
+                        v_subTotalSize = ui.originalSize.height + ui.originalElement.next().outerHeight();
+                    },
+                    stop: function(event, ui){
+                        var cellPercentHeight = 100 * ui.originalElement.outerHeight(true) / $("#" + v_mainId).height();
+                        ui.originalElement.height(cellPercentHeight + '%');
+                        var nextCell = ui.originalElement.next();
+                        var nextPercentHeight = 100 * ($("#" + v_mainId).outerHeight() - getHeight(ui)) / $("#" + v_mainId).height();
+                        nextCell.height(nextPercentHeight + '%');
+                        ui.originalElement.trigger("resize");
+                        ui.originalElement.next().trigger("resize");
+                    },
+                    resize: function(event, ui){
+                        if (v_subTotalSize - ui.size.height < 10) {
+                            ui.size.height = v_subTotalSize - 10;
+                        }
+                        ui.originalElement.next().height($("#" + v_mainId).height() - getHeight(ui));
+                        // the resize triggers a resize event automatically on the original element here, but not in the stop function
+                        ui.originalElement.next().trigger("resize");
+                    }
+                };
+            } else {
+                cssToSet = "width";
+                options = {
+                    handles: "e",
+                    start: function(event, ui){
+                        v_subTotalSize = ui.originalSize.width + ui.originalElement.next().outerWidth();
+                    },
+                    stop: function(event, ui){
+                        var cellPercentWidth = 100 * ui.originalElement.outerWidth(true) / $("#" + v_mainId).width();
+                        ui.originalElement.width(cellPercentWidth + '%');
+                        var nextCell = ui.originalElement.next();
+                        var nextPercentWidth = 100 * ($("#" + v_mainId).width() - getWidth(ui)) / $("#" + v_mainId).width();
+                        nextCell.width(nextPercentWidth + '%');
+                        ui.originalElement.trigger("resize");
+                        ui.originalElement.next().trigger("resize");
+                    },
+                    resize: function(event, ui){
+                        if (v_subTotalSize - ui.size.width < 10) {
+                            ui.size.width = v_subTotalSize - 10;
+                        }
+                        ui.originalElement.next().width($("#" + v_mainId).width() - getWidth(ui));
+                        ui.originalElement.next().trigger("resize");
+                    }
+                };
+            }
+
+            for (var i = 0; i < resizables.length - 1; ++i) {
+                $(resizables[i]).resizable(options);
+            }
+        }
+    };
+
+    function getWidth(ui) {
+        var width = 0;
+        $("#" + v_mainId + " > div").each(function() {
+            if ($(this)[0] == ui.originalElement[0]) {
+                width += ui.size.width;
+            }
+            else if ($(this)[0] != ui.originalElement.next()[0]) {
+                width += $(this).outerWidth(true);
+            }
+        });
+        return width;
+    }
+
+    function getHeight(ui) {
+        var height = 0;
+        $("#" + v_mainId + " > div").each(function() {
+            if ($(this)[0] == ui.originalElement[0]) {
+                height += ui.size.height;
+            }
+            else if ($(this)[0] != ui.originalElement.next()[0]) {
+                height += $(this).outerHeight(true);
+            }
+        });
+        return height;
+    }
+}
+
+CView_Aligner.getHelp = function() {
+    return "An aligner that aligns connected views either horizontally or vertically.\n" +
+        "It can calculate the width or height of its child views from flex if a flexAligner viewmodel is connected.\n";
+};
+
+CView_Aligner.expectsInterface = function() {
+    return [
+        {
+            "optional": ["getChildSizes"]
+        },
+        {
+            "optional": ["getState"]
+        }
+    ];
+};
+
+CView_Aligner.getCustomDataSchema = function() {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CView_Aligner",
+        "type": "object",
+        "properties": {
+            "orientation": {
+                "description": "The orientation of the aligner (default horizontal)",
+                "type": "string",
+                "enum": ["horizontal", "vertical"],
+                "default": "vertical"
+            },
+            "flexCalculation": {
+                "description": "Whether the aligner uses the subviews' flex to calculate the width / height of them",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            },
+            "resizable": {
+                "description": "Whether the subviews can be resized",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            },
+            "existing": {
+                "description": "Whether the html for the aligner already exists and does not need to be created",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            }
+        },
+        "additionalProperties": false
+    };
+    $.extend(true, schema, ViewUtils.commonViewSchema);
+    return schema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_Aligner.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_AutoGui.css b/htdocs/WebApplicationFramework/Views/View_AutoGui.css
new file mode 100644
index 0000000..19879f1
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_AutoGui.css
@@ -0,0 +1,20 @@
+.coloredDiv {
+  overflow: hidden;
+  width: 100%;
+  margin: 0;
+  padding: 0;
+  list-style: none;
+  #border: 1px solid #a1a1a1;
+  #background-color: #d2dBFD;
+  padding-left:100px;
+  cursor: pointer;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.leftDiv {
+  position: relative;
+  left: -90px;
+  overflow: hidden;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_AutoGui.js b/htdocs/WebApplicationFramework/Views/View_AutoGui.js
new file mode 100644
index 0000000..f2df699
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_AutoGui.js
@@ -0,0 +1,181 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+/** Functionality to help building some GUI elements automatically. If used, should belong to application's view part. */
+
+function CAutoGuiView(aViewModels, aID, aParentID)
+{
+    "use strict";
+    var mID = aID;
+    var mParentID = aParentID;
+    var mViewModel = aViewModels[0];
+
+    /** public functions */
+    this.applicationCreated = function() {
+        $("#" + mParentID).append('<div id="' + mID + '"></div>');
+        
+        $("#" + mID).on('click', action);
+    };
+
+    this.refresh = function(aFullRefresh)
+    {
+        var aData = mViewModel.getResponseElement();
+        if (aFullRefresh)
+        {
+            var lMainDivObj = document.getElementById(mID);
+            if (lMainDivObj)
+            {
+                lMainDivObj.innerHTML = null;
+                buildElementFromData(lMainDivObj, aData, 1, '');
+            }
+        }
+        else
+        {
+            buildElementFromData(null, aData, 1, '', true);
+        }
+    };
+
+    /** private functions */
+    
+    function action(e)
+    {
+        var lCklickedExpandedGetData = e.target.getData;
+        if (lCklickedExpandedGetData != null)
+        {
+            var lOrigGetDataRef = lCklickedExpandedGetData.origRq;
+            var lIsContainer = e.target.id.search("_elem") > 0;
+            var lIsText = e.target.id.search("_txt") > 0;
+            mViewModel.command(lCklickedExpandedGetData, lOrigGetDataRef, e.target.innerHTML, lIsContainer, lIsText);
+        }
+    }
+    
+    function buildElementFromData(p_htmlDiv, p_responseMergedRequest, p_nestingLevel, p_childDivId, p_reuseObjects, p_index)
+    {
+        var lIdStr;
+        var v_reuseObjects = (p_reuseObjects === true);
+        
+        if (p_responseMergedRequest && p_responseMergedRequest.length) // childVals or root list
+        {
+            for (var i = 0; i < p_responseMergedRequest.length; i++)
+            {
+                lIdStr = p_childDivId + "_" + i;
+                if (p_childDivId === "")
+                    lIdStr = i;
+                buildElementFromData(p_htmlDiv, p_responseMergedRequest[i], p_nestingLevel + 1, lIdStr, v_reuseObjects);
+                if (!v_reuseObjects)
+                    addSeparatorLine(p_htmlDiv);
+            }
+        }
+        else if (p_responseMergedRequest && p_responseMergedRequest.node)
+        {
+            var lObj;
+            var lNodeText = p_responseMergedRequest.node.val /*+ " / " + p_childDivId*/;
+            if (v_reuseObjects)
+            {
+                lObj = document.getElementById(p_childDivId + "_txt");
+                if (lObj)
+                    lObj.innerHTML = lNodeText;
+            }
+            else if (p_responseMergedRequest.getData)
+            {
+                var lTooltip = "Source: " + p_responseMergedRequest.getData.source + "\nElement: " + p_responseMergedRequest.getData.element;
+                if (p_responseMergedRequest.getData.ptcname && p_responseMergedRequest.getData.length > 0)
+                    lTooltip += "\nPtcName: " + p_responseMergedRequest.getData.ptcname;
+                if (p_responseMergedRequest.getData.params)
+                    for (var i = 0; i < p_responseMergedRequest.getData.params.length; i++)
+                        lTooltip += "\nParam " + i + " - " + p_responseMergedRequest.getData.params[i].paramName + ": " + p_responseMergedRequest.getData.params[i].paramValue;
+                var lElementText;
+                if (!isvalue(p_index) || p_index === 0)
+                    lElementText = p_responseMergedRequest.getData.element + ":";
+                lObj = addElementToObj(p_htmlDiv, lNodeText /*+ "  " + p_childDivId*/, p_childDivId, p_nestingLevel, lTooltip, lElementText, p_responseMergedRequest.getData);
+            }
+            if (p_responseMergedRequest.node.childVals)
+                buildElementFromData(lObj, p_responseMergedRequest.node.childVals, p_nestingLevel, p_childDivId, v_reuseObjects);
+        }
+        else if (p_responseMergedRequest && p_responseMergedRequest.list)
+        {
+            for (var i = 0; i < p_responseMergedRequest.list.length; i++)
+            {
+                lIdStr = p_childDivId + "_" + i;
+                buildElementFromData(p_htmlDiv, p_responseMergedRequest.list[i], p_nestingLevel + 1, lIdStr, v_reuseObjects, i);
+            }
+        }
+        /*
+        else
+        {
+            //console.log("unhandled:", p_responseMergedRequest);
+        }
+        */
+    }
+
+	/** private functions */
+    function getRandomColor(aN) {
+        var letters = '0123456789ABCDEF'.split('');
+        var color = '#';
+        for (var i = 0; i < 6; i++)
+            color += letters[Math.floor((aN * 167654387673 * i + 984) % 8) + 6];
+        return color;
+    }
+
+    function addElementToObj(p_htmlDiv, aText, aID, aNestingLevel, aTooltip, aElement, aGetData)
+    {
+        var lDivDiv = document.createElement("DIV");
+        lDivDiv.getData = aGetData;
+        if (aElement)
+        {
+            var lElementDiv = document.createElement("DIV");
+            lElementDiv.innerHTML = aElement;
+            lElementDiv.id = aID + "_elem";
+            lElementDiv.setAttribute("class", "leftDiv");
+            lElementDiv.getData = aGetData;
+            lDivDiv.appendChild(lElementDiv);
+        }
+        var lTextDiv = document.createElement("DIV");
+        lTextDiv.innerHTML = aText;
+        lTextDiv.id = aID + "_txt";
+        lTextDiv.getData = aGetData;
+        lDivDiv.appendChild(lTextDiv);
+        lDivDiv.id = aID;
+        if (aTooltip)
+            lDivDiv.title = aTooltip;
+        lDivDiv.setAttribute("class", "coloredDiv");
+        lDivDiv.style.backgroundColor = getRandomColor(aNestingLevel);
+        p_htmlDiv.appendChild(lDivDiv);
+        return p_htmlDiv.childNodes[p_htmlDiv.childNodes.length - 1];
+    }
+
+    function addSeparatorLine(p_htmlDiv)
+    {
+        var lDiv = document.createElement("DIV");
+        lDiv.setAttribute("class", "line");
+        if (p_htmlDiv) p_htmlDiv.appendChild(lDiv);
+    }    
+}
+
+CAutoGuiView.getHelp = function() {
+    return "This view can be used to visualize the whole response tree.";
+};
+
+CAutoGuiView.expectsInterface = function() {
+    return [
+        {
+            "mandatory": ["getResponseElement", "command"]
+        }
+    ];
+};
+
+CAutoGuiView.getCustomDataSchema = function() {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CAutoGuiView",
+        "type": "object",
+        "properties": {},
+        "additionalProperties": false
+    };
+    $.extend(true, schema, ViewUtils.commonViewSchema);
+    return schema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_AutoGui.js
diff --git a/htdocs/WebApplicationFramework/Views/View_BasicButton.css b/htdocs/WebApplicationFramework/Views/View_BasicButton.css
new file mode 100644
index 0000000..202dd17
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_BasicButton.css
@@ -0,0 +1,43 @@
+.BasicButton {
+    box-sizing: border-box;
+}
+
+.BasicButton > BUTTON {
+    font-family:"Arial";
+    /*font-size:11px;*/
+    font-weight: bold;
+    color: #333333;
+    cursor:pointer;
+    outline:none;
+    background-image: linear-gradient(to bottom, #FFFFFF, #e2e1e1);
+	text-align: center;
+    vertical-align: middle;
+    height: 25px;
+    overflow: hidden;
+}
+
+.BasicButton > BUTTON:hover {
+    color: #58585a;
+    background-image: linear-gradient(to bottom,#e2e1e1, #FFFFFF);
+}
+
+.BasicButton > BUTTON:disabled {
+    color: #999999;
+    background-color: #AAAAAA;
+}
+
+.BasicButton > BUTTON SPAN {
+	display: inline-block; /* If you remove this, the SPAN that encloses the IMG will not be the same height. Which is most likely a problem. */
+}
+
+.BasicButton > BUTTON IMG {
+    height: 16px;
+    width: 16px;
+	vertical-align: middle; /* If you remove this, the IMG will be centered and the text will valign to baseline. */
+	margin-right: 5px; /* Distance between image and text */
+}
+
+.BasicButton > BUTTON LABEL {
+	vertical-align: middle;
+	margin-right: 5px;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_BasicButton.js b/htdocs/WebApplicationFramework/Views/View_BasicButton.js
new file mode 100644
index 0000000..860a9f3
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_BasicButton.js
@@ -0,0 +1,173 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_BasicButton(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+
+    /** constructor */
+
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_BasicButton)[0];
+    var v_conditionViewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_BasicButton)[1];
+    var v_mainId = p_mainId;
+    var v_parentId = p_parentId;
+    var v_customData = p_data;
+
+    var v_label;
+    var v_value = -1;
+
+    var v_this = this;
+
+    /** public functions */
+
+    this.applicationCreated = function() {
+        if (v_viewmodel != undefined) {
+            $("#" + v_parentId).append(getHtml());
+            if (v_customData.isElementLabelPresent) {
+                v_label = ViewUtils.addLabel(v_mainId, v_customData.elementText);
+            }
+            if (v_customData.class != undefined) {
+                $("#" + v_mainId).addClass(v_customData.class);
+            } else {
+                $("#" + v_mainId).addClass("BasicButton");
+            }
+            setupCallbacks();
+            ViewUtils.addTooltip(v_mainId, v_customData);
+        }
+    };
+
+    this.refresh = function(p_fullRefresh) {
+        if (v_viewmodel != undefined) {
+            if (ViewUtils.checkVisibility(v_conditionViewmodel, v_mainId)) {
+                var dataObj = v_viewmodel.getListWithElementInfo();
+                if (dataObj == undefined || dataObj.values[0] == undefined) {
+                    return;
+                }
+
+                v_value = parseInt(dataObj.values[0].val) == NaN ? v_value : parseInt(dataObj.values[0].val);
+
+                if (v_customData.isElementLabelPresent && v_customData.elementText == undefined) {
+                    v_label.text(dataObj.values[0].element);
+                }
+
+                if (v_customData.text == undefined && v_customData.showLabel !== false) {
+                    $("#" + v_mainId + " > button > span > label").text(dataObj.values[0].element);
+                }
+
+                if (v_customData.disabled !== true && dataObj.values[0] != undefined && dataObj.values[0].isWritable) {
+                    $("#" + v_mainId + " > button").prop('disabled', false);
+                } else {
+                    $("#" + v_mainId + " > button").prop('disabled', true);
+                }
+            }
+        }
+    };
+
+    /** protected functions */
+
+    this.onClick = function() {
+        v_viewmodel.setValue(0, ((v_customData.incrementValue) ? v_value + 1 : v_value));
+    };
+
+    this.onMiddleClick = function() {};
+
+    /** private functions */
+
+    function getHtml() {
+        var html = '<div id="' + v_mainId + '"><button><span>';
+        var img = '';
+        var label = '';
+
+        if (v_customData.img != undefined) {
+            img += '<img ';
+            img += 'src="' + v_customData.img + '" ';
+            img += '>';
+        }
+
+        if (v_customData.showLabel !== false) {
+            label += '<label>';
+            if (v_customData.text != undefined) {
+                label += v_customData.text;
+            }
+            label += '</label>';
+        }
+
+        if (v_customData.imagePosition == "right") {
+            html += label;
+            html += img;
+        } else {
+            html += img;
+            html += label;
+        }
+
+        html += '</span></button></div>';
+        return html;
+    }
+
+    function setupCallbacks() {
+        $("#" + v_mainId + " > button").click(v_this.onClick).mouseup(v_this.onMiddleClick);
+    }
+}
+
+CView_BasicButton.getHelp = function() {
+    return "A simple button view that can contain a text and an image.";
+};
+
+CView_BasicButton.expectsInterface = function() {
+    return [
+        {
+            "mandatory": ["setValue", "getListWithElementInfo"]
+        },
+        {
+            "optional": ["getState"]
+        }
+    ];
+};
+
+CView_BasicButton.getCustomDataSchema = function() {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CView_BasicButton",
+        "type": "object",
+        "properties": {
+            "text": {
+                "description": "The button text (if it is undefined, the request element will be used)",
+                "type": "string"
+            },
+            "showLabel": {
+                "description": "Whether the text is visible on the button (default true)",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": false
+            },
+            "img": {
+                "description": "The button image",
+                "type": "string",
+                "default": "CustomizableContent/CustomizableApp/res/start.png"
+            },
+            "imagePosition": {
+                "description": "The position of the image relative to the text (default left)",
+                "type": "string",
+                "enum": ["left", "right"],
+                "default": "right"
+            },
+            "incrementValue": {
+                "description": "Increment the value of the connected data element (default false)",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            },
+            "class": {
+                "description": "The css class of the button",
+                "type": "string",
+                "default": "BasicButton"
+            }
+        },
+        "additionalProperties": false
+    };
+    $.extend(true, schema, ViewUtils.commonViewSchema, ViewUtils.commonElementSchema);
+    return schema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_BasicButton.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_ButtonForCodeEditing.js b/htdocs/WebApplicationFramework/Views/View_ButtonForCodeEditing.js
new file mode 100644
index 0000000..b9eea8e
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ButtonForCodeEditing.js
@@ -0,0 +1,192 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_ButtonForCodeEditing(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+
+    /** constructor */
+
+    var v_id = p_mainId;
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_ButtonForCodeEditing)[0];
+    var v_data = p_data;
+    if (v_data.tooltip == undefined && v_data.schema != undefined) {
+        v_data.tooltip = "Middle click to edit with json editor.";
+    }
+
+    var base = new CView_BasicButton(p_viewmodels, p_mainId, p_parentId, p_data);
+
+    this.applicationCreated = base.applicationCreated;
+    this.refresh = base.refresh;
+
+    base.onClick = function() {
+        if (v_data.jsonEditor) {
+            openEditor(CView_JSONEditor);
+        } else {
+            openEditor(CView_CodeEditor);
+        }
+    }
+
+    base.onMiddleClick = function(e) {
+        function schemaArrived(response) {
+            v_data.schema = JSON.parse(response[0]['node']['val']);
+            openTheEditor();
+        }
+
+        function openTheEditor() {
+            if (v_data.schema == undefined || v_data.jsonEditor) {
+                openEditor(CView_CodeEditor);
+            } else {
+                openEditor(CView_JSONEditor);
+            }
+        }
+
+        e.preventDefault();
+        e.stopPropagation();
+
+        if (e.which == 2) {
+            if (v_data.schema == undefined) {
+                v_viewmodel.getDataList(v_data.schemaRequest, schemaArrived);
+            } else {
+                openTheEditor();
+            } 
+        }
+    }
+
+    function openEditor(EditorClass) {
+        $('#' + v_id + '_Editor').remove();
+
+        var params = [];
+        var data = v_viewmodel.getListWithElementInfo();
+        if (data != undefined && data.values[0] != undefined) {
+            for (var i = 0; i < data.values.length; ++i) {
+                params.push(data.values[i].val)
+            }
+        }
+        var viewmodel = new ViewmodelForView(params);
+        var customData = {
+            'editorType': 'json',
+            'manualSaveRequired': true,
+            'closeable': true,
+            'draggable': true,
+            'headerText': 'Editor',
+            'formatAllowed': true,
+            'css': {
+                'height': '600px',
+                'width': '1200px',
+                'z-index': 20
+            },
+            'offset': {
+                'left': $(window).width() / 2 - 400,
+                'top': 100,
+            }
+        }
+
+        var editor = new EditorClass(
+            [viewmodel],
+            v_id + '_Editor',
+            'TSGuiFrameworkMain',
+            customData
+        );
+
+        editor.applicationCreated();
+        ViewUtils.applyCss(customData, v_id + '_Editor');
+        editor.refresh(true);
+    }
+
+    function ViewmodelForView(params) {
+        var v_request = JSON.stringify(v_data.request);
+        for (var i = 0; i < params.length; ++i) {
+            v_request = v_request.replace('%Param_' + i + '%', params[i]);
+        }
+        v_request = JSON.parse(v_request);
+
+        function createSetData(content) {
+            var setData = mcopy(v_request);
+            setData[0]['setData'] = setData[0]['getData'];
+            setData[0]['getData'] = undefined;
+            setData[0]['setData']['content'] = content;
+            setData[0]['setData']['tp'] = 4;
+            return setData;
+        }
+
+        this.getJSONData = function(callback) {
+            function responseArrived(response) {
+                if (response.length > 0 && response[0]['node'] != undefined) {
+                    callback(JSON.parse(response[0]['node']['val']));
+                } else {
+                    callback('');
+                }
+            }
+
+            v_viewmodel.getDataList(v_request, responseArrived);
+        };
+
+        this.setJSONData = function(data) {
+            v_viewmodel.getDataList(createSetData(JSON.stringify(data, null, 4)), function(){});
+        };
+
+        this.getSchema = function() {
+            return v_data.schema;
+        };
+
+        this.getTextData = function(callback) {
+            function responseArrived(response) {
+                if (response.length > 0 && response[0]['node'] != undefined) {
+                    callback(response[0]['node']['val']);
+                } else {
+                    callback('');
+                }
+            }
+
+            v_viewmodel.getDataList(v_request, responseArrived);
+        };
+
+        this.setTextData = function(data) {
+            v_viewmodel.getDataList(createSetData(JSON.stringify(JSON.parse(data), null, 4)), function(){});
+        };
+    }
+
+}
+
+CView_ButtonForCodeEditing.getHelp = function() {
+    return "A button view that can be used to create an editor view.";
+};
+
+CView_ButtonForCodeEditing.expectsInterface = function() {
+    return CView_BasicButton.expectsInterface();
+};
+
+CView_ButtonForCodeEditing.getCustomDataSchema = function() {
+    var baseSchema = CView_BasicButton.getCustomDataSchema();
+    var schema = {
+        "properties": {
+            "request": {
+                "description": "The request the editor can use to get and set its data. %ParamX%, where X is a number will be replaced by data received from the connected viewmodel.",
+                "type": "array",
+                "format": "tabs",
+                "items": {
+                    "type": "object"
+                }
+            },
+            "schema": {
+                "description": "The json schema that the json editor will use.",
+                "type": "object"
+            },
+            "schemaRequest": {
+                "description": "The request list to get the json schema that the json editor will use.",
+                "type": "array"
+            },
+            "jsonEditor": {
+                "description": "Whether we use json editor by default.",
+                "type": "boolean",
+                "format": "checkbox"
+            }
+        }
+    };
+    $.extend(true, baseSchema, schema);
+    return baseSchema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_ButtonForCodeEditing.js
diff --git a/htdocs/WebApplicationFramework/Views/View_ButtonForDownload.js b/htdocs/WebApplicationFramework/Views/View_ButtonForDownload.js
new file mode 100644
index 0000000..aee58aa
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ButtonForDownload.js
@@ -0,0 +1,45 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_ButtonForDownload(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+
+    /** constructor */
+
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_ButtonForDownload)[0];
+    var v_data = p_data;
+    var base = new CView_BasicButton(p_viewmodels, p_mainId, p_parentId, p_data);
+
+    this.applicationCreated = base.applicationCreated;
+    this.refresh = base.refresh;
+
+    function responseArrived(response) {
+        var data = v_viewmodel.getListWithElementInfo();
+        if (data == undefined || data.values[0] == undefined) {
+            return;
+        }
+
+        var fileName = data.values[0].val;
+        window.open(fileName, '_blank');
+    }
+
+    base.onClick = function() {
+        v_viewmodel.setValue(0, 0, undefined, undefined, responseArrived);
+    }
+}
+
+CView_ButtonForDownload.getHelp = function() {
+    return "A button view that can be used to download data to a file.";
+};
+
+CView_ButtonForDownload.expectsInterface = function() {
+    return CView_BasicButton.expectsInterface();
+};
+
+CView_ButtonForDownload.getCustomDataSchema = function() {
+    return CView_BasicButton.getCustomDataSchema();
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_ButtonForDownload.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_ButtonForUrlOpen.js b/htdocs/WebApplicationFramework/Views/View_ButtonForUrlOpen.js
new file mode 100644
index 0000000..847b0f2
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ButtonForUrlOpen.js
@@ -0,0 +1,94 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_ButtonForUrlOpen(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+
+    /** constructor */
+
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_ButtonForUrlOpen)[0];
+    var v_data = p_data;
+    var v_midleClickOpensTab = false;
+    if (v_data.tooltip == undefined) {
+        v_data.tooltip = "Middle click to open in a new tab.";
+    }
+    if (v_data.paramKey == undefined) {
+        v_data.paramKey = "location";
+    }
+    if (v_data.paramKey == "location") {
+        v_midleClickOpensTab = true;
+    }
+
+    var base = new CView_BasicButton(p_viewmodels, p_mainId, p_parentId, p_data);
+
+    this.applicationCreated = base.applicationCreated;
+    this.refresh = base.refresh;
+
+    base.onClick = function() {
+        var data = v_viewmodel.getListWithElementInfo();
+        var value;
+        if (data != undefined && data.values[0] != undefined) {
+            value = data.values[0].val;
+        }
+
+        var additionalData = {
+            "setAppParams": {
+                "appName": v_data.appName,
+                "params": [
+                    {
+                        "key": v_data.paramKey,
+                        "value": value
+                    }
+                ]
+            }
+        }
+        v_viewmodel.setValue(undefined, undefined, undefined, undefined, undefined, additionalData);
+
+        additionalData = {
+            "loadApp": v_data.appName
+        }
+        v_viewmodel.setValue(undefined, undefined, undefined, undefined, undefined, additionalData);
+    }
+
+    base.onMiddleClick = function(e) {
+        if (e.which != 2 || !v_midleClickOpensTab) {
+            return;
+        }
+
+        var data = v_viewmodel.getListWithElementInfo();
+        if (data == undefined || data.values[0] == undefined) {
+            return;
+        }
+        window.open(data.values[0].val, '_blank');
+    }
+}
+
+CView_ButtonForUrlOpen.getHelp = function() {
+    return "A button view that can be used to set the location of a WebpageFrame application and load that app.";
+};
+
+CView_ButtonForUrlOpen.expectsInterface = function() {
+    return CView_BasicButton.expectsInterface();
+};
+
+CView_ButtonForUrlOpen.getCustomDataSchema = function() {
+    var baseSchema = CView_BasicButton.getCustomDataSchema();
+    var schema = {
+        "properties": {
+            "appName": {
+                "description": "The name of the application",
+                "type": "string"
+            },
+            "paramKey": {
+                "description": "The name of the parameter key",
+                "type": "string"
+            }
+        }
+    };
+    $.extend(true, baseSchema, schema);
+    return baseSchema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_ButtonForUrlOpen.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Chart.css b/htdocs/WebApplicationFramework/Views/View_Chart.css
new file mode 100644
index 0000000..f3c7217
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Chart.css
@@ -0,0 +1,23 @@
+.BasicChart {
+    box-sizing: border-box;
+}
+
+.BasicChart.RotatedXAxis .flot-x-axis .flot-tick-label {
+    white-space: nowrap;
+    transform: translate(-9px, 0) rotate(-60deg);
+    text-indent: -100%;
+    transform-origin: top right;
+    text-align: right !important;
+}
+
+.BasicChart .legend {
+    cursor: pointer;
+}
+
+.BasicChart .legend table td {
+    opacity: 0.8;
+}
+
+.BasicChart_SeriesDisabled {
+    color: #aaaaaa;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Chart.js b/htdocs/WebApplicationFramework/Views/View_Chart.js
new file mode 100644
index 0000000..dfea303
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Chart.js
@@ -0,0 +1,364 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_Chart(p_viewmodels, p_mainId, p_parentId, p_data) {

+    "use strict";

+    

+    /** constructor */

+    

+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_Chart)[0];

+    var v_conditionViewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_Chart)[1];

+    var v_mainId = p_mainId;

+    var v_parentId = p_parentId;

+    var v_customData = p_data;

+

+    var v_chart;

+    

+    var v_this = this;

+    

+    /** public functions */

+

+    this.applicationCreated = function() {

+        if (v_viewmodel != undefined) {

+            $("#" + v_parentId).append(getHtml());

+

+            var data = [];

+            var options = {

+                series: {

+                    lines: {

+                        steps: false,

+                        fill: false

+                    },

+                    bars: {

+                        align: 'center',

+                        fill: 1,

+                        lineWidth: 0

+                    }

+                },

+                xaxis: {

+                    panRange: [0, 0],

+                    zoomRange: [5, null]

+                },

+                yaxis: {

+                    panRange: [0, 0],

+                    zoomRange: [5, null]

+                },

+                legend: {

+                    show: true,

+                    backgroundOpacity: 0.5,

+                    noColumns: 1

+                },

+                grid: {

+                    autoHighlight: true,

+                    hoverable: true,

+                    borderWidth: 0,

+                    margin: {}

+                }

+            };

+            

+            if (v_customData.type == "timeseries") {

+                options.xaxis.mode = "time";

+                options.xaxis.timeformat = "%H:%M:%S";

+                //options.grid.margin.bottom = 10;

+            } else if (v_customData.type == "distribution") {

+                options.grid.margin.bottom = 80;

+                $("#" + v_mainId).addClass("RotatedXAxis");

+            }

+            

+            if (v_customData.yTicksFormat == "percent") {

+                options.yaxis.tickFormatter = tickFormatterPercent;

+            } else if (v_customData.yTicksFormat == "data") {

+                options.yaxis.tickFormatter = tickFormatterData;

+            } else if (v_customData.yTicksSuffix != undefined) {

+                options.yaxis.tickFormatter = tickFormatterCustom;

+            }

+            

+            if (v_customData.zoomAndPan !== false) {

+                options.zoom = {interactive: true};

+                options.pan = {interactive: true};

+            }

+            

+            v_chart = $.plot($("#" + v_mainId), data, options);

+            

+            if (v_customData.title != undefined) {

+                v_chart.hooks.drawOverlay.push(function(plot, cvs) {

+                    if(!plot) {

+                        return;

+                    }

+                    

+                    var cvsWidth = cvs.canvas.width / 2;

+                    var text = v_customData.title;

+                    cvs.font = "bold 16px Open Sans";

+                    cvs.fillStyle = "#666666";

+                    cvs.textAlign = "center";

+                    cvs.globalAlpha = "0.8";

+                    cvs.fillText(text, cvsWidth, 30);

+                    return cvs;

+                });

+            }

+            

+            setupCallbacks();

+        }

+    };

+    

+    this.refresh = function(p_fullRefresh) {

+        if (v_viewmodel != undefined && ViewUtils.checkVisibility(v_conditionViewmodel, v_mainId)) {

+            var chartData = v_viewmodel.getChartData();

+            if (chartData.dataSets.length > 0) {

+                $("#" + v_mainId).removeClass("hidden");

+                v_chart.getAxes().xaxis.options.ticks = chartData.ticks;

+                if (v_customData.zoomAndPan !== false) {

+                    setNavigationRanges(chartData.navigationRanges);

+                }

+                

+                v_chart.setData(chartData.dataSets);

+                

+                v_chart.setupGrid();

+                v_chart.draw();

+                

+                updateLegend(chartData.dataSets.length);

+                

+                if (v_customData.showValues) {

+                    createLabelsAtTop();

+                }

+            } else {

+                $("#" + v_mainId).addClass("hidden");

+            }

+        }

+    };

+    

+    /** private functions */

+    

+    function tickFormatterPercent(val, axis) {

+        return val.toFixed(axis.tickDecimals) + "%";

+    }

+    

+    function tickFormatterData(val, axis) {

+        if (val > 1000) {

+            return (val / 1000).toFixed(axis.tickDecimals) + " MB";

+        } else {

+            return val.toFixed(axis.tickDecimals) + " KB";

+        }

+    }

+    

+    function tickFormatterCustom(val, axis) {

+        return val.toFixed(axis.tickDecimals) + v_customData.yTicksSuffix;

+    }

+    

+    function setNavigationRanges(ranges) {

+        var xAxis = v_chart.getAxes().xaxis;

+        var yAxis = v_chart.getAxes().yaxis;

+        

+        xAxis.options.panRange[0] = ranges.x.pan.min;

+        xAxis.options.panRange[1] = ranges.x.pan.max;

+        xAxis.options.zoomRange[0] = ranges.x.zoom.min;

+        xAxis.options.zoomRange[1] = ranges.x.zoom.max;

+        

+        yAxis.options.panRange[0] = ranges.y.pan.min;

+        yAxis.options.panRange[1] = ranges.y.pan.max;

+        yAxis.options.zoomRange[0] = ranges.y.zoom.min;

+        yAxis.options.zoomRange[1] = ranges.y.zoom.max;

+    }

+    

+    function createLabelsAtTop() {

+        var ctx = v_chart.getCanvas().getContext("2d");

+        var dataSets = v_chart.getData();

+        for (var j = 0; j < dataSets.length; ++j) {

+            if (v_viewmodel.isSeriesVisible(j)) {

+                var data = dataSets[j].data;

+                var xaxis = v_chart.getXAxes()[0];

+                var yaxis = v_chart.getYAxes()[0];

+                var offset = v_chart.getPlotOffset();

+                ctx.fillStyle = dataSets[j].color;

+                for (var i = 0; i < data.length; i++){

+                    var text = data[i][1] + '';

+                    var metrics = ctx.measureText(text);

+                    var xPos = (xaxis.p2c(data[i][0])+offset.left) - metrics.width / 2;

+                    var yPos = yaxis.p2c(data[i][1]) + offset.top - 5;

+                    ctx.fillText(text, xPos, yPos);

+                }

+            }

+        }

+    }

+    

+    function getHtml() {

+        var height = "400px";

+        if (v_customData.height != undefined) {

+            height = v_customData.height;

+        }

+        

+        var width = "800px";

+        if (v_customData.width != undefined) {

+            width = v_customData.width;

+        }

+        

+        return '<div id="' + v_mainId + '" class="BasicChart" style="width: ' + width + '; height: ' + height + ';"></div>';

+    }

+    

+    function updateLegend(numberOfEntries) {

+        v_chart.getOptions().legend.noColumns = Math.ceil(numberOfEntries / 15);

+        

+        var counter = 0;

+        var rows = $("#" + v_mainId + " .legend tr");

+        for (var i = 0; i < rows.length; ++i) {

+            var cols = $(rows[i]).find("td");

+            for (var j = 0; j < cols.length; ++j) {

+                if (j % 2 == 1) {

+                    if (v_viewmodel.isSeriesVisible(counter)) {

+                        $(cols[j]).removeClass("BasicChart_SeriesDisabled");

+                    } else {

+                        $(cols[j]).addClass("BasicChart_SeriesDisabled");

+                    }

+                    ++counter;

+                }

+            }

+        }

+    }

+    

+    function resetNavigation() {

+        var axes = v_chart.getAxes();

+        var xaxis = axes.xaxis.options;

+        var yaxis = axes.yaxis.options;

+        xaxis.min = null;

+        xaxis.max = null;

+        yaxis.min = null;

+        yaxis.max = null;

+

+        v_chart.setupGrid();

+        v_chart.draw();

+    }

+    

+    function saveAsImage() {

+        html2canvas(document.getElementById(v_mainId), {

+            onrendered: function(canvas) {

+                var dataURL = canvas.toDataURL('image/png');

+                var html = '<a href="' + dataURL + '" download="chart.png" id="chart_download">DOWNLOAD</a>';

+                $("body").append(html);

+                $("#chart_download")[0].click();

+                $("#chart_download").remove();

+            }

+        });

+    }

+    

+    function setupCallbacks() {

+        $("#" + v_mainId).on("plothover", function(event, pos, data) {

+            if (data != undefined) {

+                if (v_customData.type == "timeseries") {

+                    $("#" + v_mainId).prop("title", data.series.label + "\nx: " + Date(data.datapoint[0]) + "\ny: " + data.datapoint[1]);

+                } else {

+                    $("#" + v_mainId).prop("title", data.series.label + "\n" + data.datapoint[1]);

+                }

+            }

+        });

+        

+        $("#" + v_mainId).on("click", ".legend td", function(a, b, c) {

+            var index = $(this).index();

+            var parent = $(this).parent();

+            var numberOfColumns = v_chart.getOptions().legend.noColumns;

+            var parentIndex = parent.index();

+            

+            var seriesIndex = parentIndex * numberOfColumns + Math.floor(index / 2);

+            

+            v_viewmodel.toggleSeries(seriesIndex);

+            v_this.refresh();

+        });

+        

+        $("#" + v_mainId).on('contextmenu', function(event) {

+            var customDataForMenu = {

+                "offset": {top: event.clientY - 5, left: event.clientX - 5}

+            };

+            var id = v_mainId + "_ContextMenu";

+            var contextMenu = new CView_ContextMenu([{

+                "getMenuElements": function() {

+                    return [{

+                        "text": "Reset Navigation",

+                        "callback": resetNavigation

+                    },

+                    {

+                        "text": "Save As Image",

+                        "callback": saveAsImage

+                    }];

+                }

+            }], id, v_parentId, customDataForMenu);

+            contextMenu.applicationCreated();

+            ViewUtils.applyCss(customDataForMenu, id);

+

+            event.preventDefault();

+            return false;

+        });

+    }

+}

+

+CView_Chart.getHelp = function() {

+    return "A chart view. Make sure that the chart has a width and a height, otherwise it will not work. By default they are set to 800px and 400px respectively. Percentages will only work when the browser can calculate them.";

+};

+

+CView_Chart.expectsInterface = function() {

+    return [

+        {

+            "mandatory": ["getChartData", "toggleSeries", "isSeriesVisible"]

+        },

+        {

+            "optional": ["getState"]

+        }

+    ];

+};

+

+CView_Chart.getCustomDataSchema = function() {

+    var schema = {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "title": "Custom data for CView_Chart",

+        "type": "object",

+        "properties": {

+            "width": {

+                "type": "string",

+                "description": "The width of the chart.",

+                "default": "800px"

+            },

+            "height": {

+                "type": "string",

+                "description": "The height of the chart.",

+                "default": "400px"

+            },

+            "showValues": {

+                "type": "boolean",

+                "format": "checkbox",

+                "description": "Whether the values are displayed.",

+                "default": true

+            },

+            "type": {

+                "type": "string",

+                "description": "The chart type.",

+                "enum": ["timeseries", "distribution"],

+                "default": "timeseries"

+            },

+            "yTicksFormat": {

+                "type": "string",

+                "description": "The format of the y axis labels. To use a custom one, use yTicksSuffix.",

+                "enum": ["percent", "data"]

+            },

+            "yTicksSuffix": {

+                "type": "string",

+                "description": "The custom suffix of the y axis labels."

+            },

+            "zoomAndPan": {

+                "type": "boolean",

+                "format": "checkbox",

+                "description": "Whether the chart can be zoomed and panned (default is true).",

+                "default": false

+            },

+            "title": {

+                "type": "string",

+                "description": "The title of the chart."

+            }

+        },

+        "additionalProperties": false,

+        "required": ["type"]

+    };

+    $.extend(true, schema, ViewUtils.commonViewSchema);

+    return schema;

+};

+

+//# sourceURL=WebApplicationFramework\Views\View_Chart.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_CheckboxOrSwitch.css b/htdocs/WebApplicationFramework/Views/View_CheckboxOrSwitch.css
new file mode 100644
index 0000000..58a3ddd
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_CheckboxOrSwitch.css
@@ -0,0 +1,33 @@
+.CheckBoxOrSwitch {
+    font-family: "Arial";
+    vertical-align: middle;
+    height: 100%;
+    box-sizing: border-box;
+}
+
+.CheckBoxOrSwitch > DIV {
+    width: 0px;
+    height: 25px;
+    display: inline-block;
+    vertical-align: middle;
+}
+
+.CheckBoxOrSwitch > IMG {
+    vertical-align: middle; /* If you remove this, the IMG will be centered and the text will valign to baseline. */
+    margin-right: 5px; /* Distance between image and text */
+    height: 25px;
+    width: 25px;
+    display: inline-block;
+}
+
+.CheckBoxOrSwitch > INPUT {
+    vertical-align: middle;
+    margin-right: 5px;
+    display: inline-block;
+}
+
+.CheckBoxOrSwitch > LABEL {
+    vertical-align: middle;
+    margin-right: 5px;
+    display: inline-block;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_CheckboxOrSwitch.js b/htdocs/WebApplicationFramework/Views/View_CheckboxOrSwitch.js
new file mode 100644
index 0000000..7534de1
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_CheckboxOrSwitch.js
@@ -0,0 +1,187 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_CheckboxOrSwitch(p_viewmodels, p_mainId, p_parentId, p_data) {

+    "use strict";

+    /** constructor */

+    

+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_CheckboxOrSwitch)[0];

+    var v_conditionViewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_CheckboxOrSwitch)[1];

+    var v_mainId = p_mainId;

+    var v_parentId = p_parentId;

+    var v_customData = p_data;

+    

+    var selector = -1;

+    var v_label;

+    var v_currentValue;

+    var v_switchDisabled = false;

+    

+    var v_this = this;

+    

+    this.applicationCreated = function() {

+        if (v_viewmodel != undefined) {

+            $("#" + v_parentId).append(getHtml());

+            if (v_customData.isElementLabelPresent) {

+                v_label = ViewUtils.addLabel(v_mainId, v_customData.elementText);

+            }

+            $("#" + v_mainId).addClass("CheckBoxOrSwitch");

+            

+            if (v_customData.isSwitch == true) {

+                $("#" + v_mainId + '_switchImg').click(function() {

+                    if (!v_switchDisabled) { v_viewmodel.setValue(0, !v_currentValue); }

+                });

+            } else {

+                $("#" + v_mainId + "_checkBox").on('change', function() {

+                    v_viewmodel.setValue(0, !v_currentValue);

+                });

+            }

+            

+            ViewUtils.addTooltip(v_mainId, v_customData);

+        }

+    };

+    

+    this.refresh = function(p_fullRefresh) {

+        if (v_viewmodel != undefined) {

+            if (ViewUtils.checkVisibility(v_conditionViewmodel, v_mainId)) {

+                var dataObject = v_viewmodel.getListWithElementInfo();

+                if (dataObject == undefined || dataObject.values[0] == undefined) {

+                    return;

+                }

+                

+                if (dataObject.values[0].val == undefined) {

+                    $("#" + v_mainId + " > *").css("display", "none");

+                    $("#" + v_mainId).addClass("NoData");

+                } else {

+                    $("#" + v_mainId + " > *").css("display", "");

+                    $("#" + v_mainId).removeClass("NoData");

+                }

+                

+                v_currentValue = dataObject.values[0].val == "true";

+                

+                if (p_fullRefresh && v_customData.isElementLabelPresent && v_customData.elementText == undefined) {

+                    v_label.text(dataObject.values[0].element);

+                }

+                

+                if (v_customData.isSwitch == true) {

+                    var temp = 0;

+                    if (dataObject.values[0].val == "true") { temp = temp + 1; }

+                    if (!dataObject.values[0].isWritable || v_customData.disabled === true) { temp = temp + 2; v_switchDisabled = true; } else { v_switchDisabled = false; }

+                    if (selector != temp) {

+                        selector = temp;

+                        $("#" + v_mainId + "_switchImg").attr("src", getImg(selector));

+                    }

+                } else {

+                    document.getElementById(v_mainId + "_checkBox").checked = ( (dataObject.values[0].val == "true") ? true : false);

+                    document.getElementById(v_mainId + "_checkBox").disabled = ( (!dataObject.values[0].isWritable || v_customData.disabled === true) ? true : false);

+                }

+                

+                $("#" + v_mainId + "_checkBoxLabel").text( (v_customData.labelText) ? v_customData.labelText : dataObject.values[0].element);

+            }

+        }

+    };

+

+    function getHtml() {

+        var label = '';

+        if (v_customData.isLabelPresent == true) {

+            label = '<label id="' + v_mainId + '_checkBoxLabel"></label>';

+        }

+        

+        var input;

+        if (v_customData.isSwitch == true) {

+            input = '<img id="' + v_mainId + '_switchImg"/>';

+        } else {

+            input = '<input type="checkbox" id="' + v_mainId + "_checkBox" + '">';

+        }

+        

+        return '<div id="' + v_mainId + '"><div></div>' + ((v_customData.alignment == "right") ? (label + input) : (input + label)) + '</div>';

+        

+    }

+    

+    function getImg(selector) {

+        var img = "";

+        switch (selector) {

+            case 0:

+                img = ( (v_customData.ImgOff) ? v_customData.ImgOff : "WebApplicationFramework/Res/switchOff.png" );

+                break;

+            case 1:

+                img = ( (v_customData.ImgOn) ? v_customData.ImgOn : "WebApplicationFramework/Res/switchOn.png" );

+                break;

+            case 2:

+                img = ( (v_customData.ImgOffD) ? v_customData.ImgOffD : "WebApplicationFramework/Res/switchOff_disabled.png" );

+                break;

+            case 3:

+                img = ( (v_customData.ImgOnD) ? v_customData.ImgOnD : "WebApplicationFramework/Res/switchOn_disabled.png" );

+                break;            

+        }

+        return img;

+    }

+}

+

+CView_CheckboxOrSwitch.getHelp = function() {

+    return "A checkbox view that can also look like a switch.";

+}

+

+CView_CheckboxOrSwitch.expectsInterface = function() {

+    return [

+        {

+            "mandatory": ["setValue", "getListWithElementInfo"]

+        },

+        {

+            "optional": ["getState"]

+        }

+    ];

+};

+

+CView_CheckboxOrSwitch.getCustomDataSchema = function() {

+    var schema = {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "title": "Custom data for CView_CheckboxOrSwitch",

+        "type": "object",

+        "properties": {

+            "isSwitch": {

+                "type": "boolean",

+                "format": "checkbox",

+                "description": "Are we a flippable switch? (by default we are a checkbox)",

+                "default": true

+            },

+            "isLabelPresent": {

+                "type": "boolean",

+                "format": "checkbox",

+                "description": "Show label next to the checkbox / switch (default false)",

+                "default": true

+            },

+            "labelText": {

+                "type": "string",

+                "description": "The text of the label next to the checkbox / switch"

+            },

+            "alignment": {

+                "type": "string",

+                "description": "The position of the label relative to the checkbox / switch (default left)",

+                "enum": ["left", "right"],

+                "default": "right"

+            },

+            "ImgOff": {

+                "type": "string",

+                "title": "Off state image's URL"

+            },

+            "ImgOffD": {

+                "type": "string",

+                "title": "Disabled off state image's URL"

+            },

+            "ImgOn": {

+                "type": "string",

+                "title": "On state image's URL"

+            },

+            "ImgOnD": {

+                "type": "string",

+                "title": "Disabled on state image's URL"

+            }

+        },

+        "additionalProperties": false

+    };

+    $.extend(true, schema, ViewUtils.commonViewSchema, ViewUtils.commonElementSchema);

+    return schema;

+};

+//# sourceURL=WebApplicationFramework\Views\View_CheckboxOrSwitch.js

diff --git a/htdocs/WebApplicationFramework/Views/View_Clients.css b/htdocs/WebApplicationFramework/Views/View_Clients.css
new file mode 100644
index 0000000..7423181
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Clients.css
@@ -0,0 +1,7 @@
+.ClientsView {
+    width: 100%;
+}
+
+.ClientsView table {
+    width: 100%;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Clients.js b/htdocs/WebApplicationFramework/Views/View_Clients.js
new file mode 100644
index 0000000..8e5613a
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Clients.js
@@ -0,0 +1,189 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_Clients(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+    
+    /** constructor */
+    
+    var v_mainId = p_mainId;
+    var v_parentId = p_parentId;
+    var v_tableId = v_mainId + "_table";
+    var v_customData = p_data;
+    var v_subviews = [];
+    
+    var v_scrollId = v_mainId + "_Scroll";
+    var scrollBar = new CView_Scroll(p_viewmodels, v_scrollId, v_mainId, p_data);
+    
+    var v_viewmodels = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_Clients);
+    var v_viewmodel = v_viewmodels[0];
+    var v_streamingViewmodel = v_viewmodels[1];
+    var v_conditionViewmodel = v_viewmodels[2];
+    var v_scrollInitialised = false;
+    
+    var v_class = "ClientsView";
+    if (v_customData.class != undefined) {
+        v_class = v_customData.class;
+    }
+    
+    /** public functions */
+
+    this.applicationCreated = function() {
+        if (v_viewmodel != undefined) {
+            $("#" + v_parentId).append(getHtml());
+            $("#" + v_mainId).css("position", "relative");
+        }
+    };
+    
+    this.refresh = function() {
+        if (v_viewmodel != undefined && ViewUtils.checkVisibility(v_conditionViewmodel, v_mainId)) {
+            var data = v_viewmodel.getViewmodelBundle();
+            createSubviews(data);
+            refreshSubviews(data);
+            refreshScroll();
+        }
+    };
+    
+    /* private functions */
+    
+    function createSubviews(data) {
+        var table = $("#" + v_tableId);
+        var existingGroups = $("#" + v_tableId + " > tbody > tr").length / 3;
+        var numberOfGroupsToCreate = data.viewmodels.length - existingGroups;
+        if (numberOfGroupsToCreate > 0) {
+            for (var i = 0; i < numberOfGroupsToCreate; ++i) {
+                var aligner1Id = v_mainId + '_aligner1_' + (existingGroups + i);
+                var aligner2Id = v_mainId + '_aligner2_' + (existingGroups + i);
+                var tableId = v_mainId + '_subTable_' + (existingGroups + i);
+                table.append(
+                    '<tr><td id="' + aligner1Id + '"></td><td id="' + aligner2Id + '"></td></tr>' + 
+                    '<tr><td colspan=2 id="' + tableId + '"></td></tr>' + 
+                    '<tr><td colspan=2><div class="line"></div></td></tr>'
+                );
+                
+                var aligner1 = new CView_ElementAligner([data.viewmodels[existingGroups + i].aligner1], aligner1Id + "_view", aligner1Id, v_customData.customDataForFirstAligner);
+                var aligner2 = new CView_ElementAligner([data.viewmodels[existingGroups + i].aligner2], aligner2Id + "_view", aligner2Id, v_customData.customDataForSecondAligner);
+                var tableSubview = new CView_ElementTable([data.viewmodels[existingGroups + i].table], tableId + "_view", tableId, v_customData.customDataForTable);
+                
+                v_subviews.push(aligner1);
+                v_subviews.push(aligner2);
+                v_subviews.push(tableSubview);
+                
+                aligner1.applicationCreated();
+                aligner2.applicationCreated();
+                tableSubview.applicationCreated();
+                
+                ViewUtils.applyCss(v_customData.customDataForFirstAligner, aligner1Id + "_view");
+                ViewUtils.processCss(v_customData.customDataForFirstAligner, aligner1Id);
+                ViewUtils.applyCss(v_customData.customDataForSecondAligner, aligner2Id + "_view");
+                ViewUtils.processCss(v_customData.customDataForSecondAligner, aligner2Id);
+                ViewUtils.applyCss(v_customData.customDataForTable, tableId + "_view");
+                ViewUtils.processCss(v_customData.customDataForTable, tableId);
+            }
+        } else if (numberOfGroupsToCreate < 0) {
+            $("#" + v_tableId + " > tbody > tr").slice((existingGroups + numberOfGroupsToCreate) * 3).remove();
+            for (var i = 0; i > 3 * numberOfGroupsToCreate; --i) {
+                v_subviews.pop();
+            }
+        }
+        
+        if (data.firstSeparatorExists) {
+            $($("#" + v_tableId + " > tbody > tr")[0]).css("display", "");
+        } else {
+            $($("#" + v_tableId + " > tbody > tr")[0]).css("display", "none");
+        }
+    }
+    
+    function refreshSubviews(data) {
+        for (var i = 0; i < v_subviews.length; ++i) {
+            v_subviews[i].refresh(data.fullRefresh);
+        }
+    }
+    
+    function refreshScroll() {
+        var isStreaming = false;
+        if (v_streamingViewmodel.isStreaming != undefined) {
+            isStreaming = v_streamingViewmodel.isStreaming();
+        }
+        if (v_scrollInitialised && !isStreaming) {
+            $("#" + v_scrollId).remove();
+            v_scrollInitialised = false;
+            $("#" + v_mainId).scrollTop(0).css("overflow-y", "auto");
+        } else if (!v_scrollInitialised && isStreaming) {
+            scrollBar.applicationCreated();
+            v_scrollInitialised = true;
+            $("#" + v_mainId).scrollTop(0).css("overflow-y", "hidden");
+        }
+        
+        if (isStreaming) {
+            scrollBar.refresh();
+        }
+    }
+    
+    function getHtml() {
+        return '' +
+            '<div id="' + v_mainId + '" class="' + v_class + '">' + 
+                '<table id="' + v_tableId + '">' +
+                    '<col width="50%">' +
+                    '<col width="50%">' +
+                '</table>' +
+            '</div>';
+    }
+}
+
+CView_Clients.getHelp = function() {
+    return "The view for the ExecCtrl clients tab. It creates 2 aligners and a table per group.";
+};
+
+CView_Clients.expectsInterface = function() {
+    var expectedInterface = CView_Scroll.expectsInterface();
+    expectedInterface.unshift({
+        "optional": ["getState"]
+    });
+    expectedInterface.unshift({
+        "optional": ["isStreaming"]
+    });
+    expectedInterface.unshift({
+        "mandatory": ["getViewmodelBundle"]
+    });
+    
+    return expectedInterface;
+};
+
+CView_Clients.getCustomDataSchema = function() {
+    var tableSchema = CView_ElementTable.getCustomDataSchema();
+    var firstAlignerSchema = CView_ElementAligner.getCustomDataSchema();
+    // yes they are the same, but ajv does not like it, when the same object can be found multiple times in the same schema...
+    var secondAlignerSchema = CView_ElementAligner.getCustomDataSchema();
+    var scrollSchema = CView_Scroll.getCustomDataSchema();
+    
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CView_Clients",
+        "type": "object",
+        "properties": {
+            "class": {
+                "description": "The css class of the view",
+                "type": "string",
+                "default": "ClientsView"
+            },
+            "hideFirstAligner": {
+                "description": "Hide the first aligner when not all of its data is visible creating a more scroll like experience (default true).",
+                "type": "boolean",
+                "default": "false"
+            },
+            "customDataForFirstAligner": firstAlignerSchema,
+            "customDataForSecondAligner": secondAlignerSchema,
+            "customDataForTable": tableSchema
+        },
+        "additionalProperties": false,
+        "required": ["customDataForFirstAligner", "customDataForSecondAligner", "customDataForTable"]
+    };
+    
+    $.extend(true, schema, scrollSchema, ViewUtils.commonViewSchema);
+    return schema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_Clients.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_CodeEditor.css b/htdocs/WebApplicationFramework/Views/View_CodeEditor.css
new file mode 100644
index 0000000..4483453
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_CodeEditor.css
@@ -0,0 +1,68 @@
+.CodeEditor {

+    width: 100%;

+    height: 100%;

+    background-color: #EEEEEE;

+    border: 2px solid #aaa;

+    box-sizing: border-box;

+}

+

+.CodeEditor_Header {

+    background-color: #888888;

+    overflow: hidden;

+    white-space: nowrap;

+    display: block;

+    height: 20px;

+    width: 100%;

+    position: relative;

+    text-align: center;

+}

+

+.CodeEditor_Header > h3 {

+    margin: auto auto;

+    height: 20px;

+    font-weight: bold;

+    text-align: center;

+    padding: 0px;

+}

+

+.CodeEditor_Header > button {

+    display: block;

+    position: absolute;

+    top: 0;

+    background-color: #d66;

+    border: 2px solid #d66;

+    font-weight: bold;

+    height: 20px;

+    color: white;

+    padding: 0px;

+}

+

+.CodeEditor_Header > button:hover {

+    background-color: #e99797;

+    border: 2px solid #e99797;

+}

+

+.CodeEditor_Editor {

+    width: 100%;

+    height: calc(100% - 20px);

+    display: block;

+}

+

+.CodeEditor_Format {

+    width: 50px;

+    left: 0;

+}

+

+.CodeEditor_Save {

+    width: 50px;

+    left: 51px;

+}

+

+.CodeEditor_Close {

+    width: 20px;

+    right: 0;

+}

+

+.CodeMirror-focused {

+    background-color: #E7E7E7;

+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_CodeEditor.js b/htdocs/WebApplicationFramework/Views/View_CodeEditor.js
new file mode 100644
index 0000000..f55c773
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_CodeEditor.js
@@ -0,0 +1,395 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_CodeEditor(p_viewmodels, p_viewId, p_parentId, p_options) {

+    if (p_options.editorType == "html") {

+        return new CView_HtmlEditor(p_viewmodels, p_viewId, p_parentId, p_options);

+    } else if (p_options.editorType == "css") {

+        return new CView_CssEditor(p_viewmodels, p_viewId, p_parentId, p_options);

+    } else if (p_options.editorType == "javascript") {

+        return new CView_JavascriptEditor(p_viewmodels, p_viewId, p_parentId, p_options);

+    } else if (p_options.editorType == "json") {

+        return new CView_JSONCodeEditor(p_viewmodels, p_viewId, p_parentId, p_options);

+    } else {

+        return new CView_BaseCodeEditor(p_viewmodels, p_viewId, p_parentId, p_options);

+    }

+}

+

+CView_CodeEditor.getHelp = function() {

+    return "A code editor view that supports validation and formatting.";

+};

+

+CView_CodeEditor.expectsInterface = function() {

+    return [

+        {

+            "mandatory": ["setTextData", "getTextData"]

+        }

+    ];

+};

+

+CView_CodeEditor.getCustomDataSchema = function() {

+    var schema = {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "title": "Custom data for CView_CodeEditor",

+        "type": "object",

+        "properties": {

+            "editorType": {

+                "description": "The type of the editor used for syntax highlighting and formaatting.",

+                "type": "string",

+                "enum": ["html", "css", "javascript", "json"]

+            },

+            "readOnly": {

+                "description": "Whether we want to allow editing.",

+                "type": "boolean",

+                "format": "checkbox",

+                "default": true

+            },

+            "headerText": {

+                "description": "The title of the editor.",

+                "type": "string"

+            },

+            "formatAllowed": {

+                "description": "Whether we want to allow formatting.",

+                "type": "boolean",

+                "format": "checkbox",

+                "default": true

+            },

+            "manualSaveRequired": {

+                "description": "Whether we must press the save button to save the data.",

+                "type": "boolean",

+                "format": "checkbox",

+                "default": true

+            },

+            "closeable": {

+                "description": "Whether we want to allow closing the editor.",

+                "type": "boolean",

+                "format": "checkbox",

+                "default": true

+            },

+            "alwaysRefresh": {

+                "description": "Always refresh the editor, not only on full refresh.",

+                "type": "boolean",

+                "format": "checkbox",

+                "default": true

+            },

+            "disableRefreshOnFocus": {

+                "description": "Disables refresh when focused.",

+                "type": "boolean",

+                "format": "checkbox",

+                "default": true

+            },

+            "focusEditorOnOpen": {

+                "description": "Whether we want to focus the editor when opening it.",

+                "type": "boolean",

+                "format": "checkbox",

+                "default": true

+            },

+            "draggable": {

+                "description": "Whether we want the editor to be draggable.",

+                "type": "boolean",

+                "format": "checkbox",

+                "default": true

+            },

+            "offset": {

+                "description": "The offset of the editor. Only works with draggable.",

+                "type": "object",

+                "properties": {

+                    "top": {

+                        "type": "integer"

+                    },

+                    "left": {

+                        "type": "integer"

+                    }

+                }

+            }

+        },

+        "additionalProperties": false

+    };

+    $.extend(true, schema, ViewUtils.commonViewSchema);

+    return schema;

+};

+

+function CView_BaseCodeEditor(p_viewmodels, p_viewId, p_parentId, p_options) {

+    "use strict";

+    var v_parentId = p_parentId;

+    var v_viewId = p_viewId;

+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_CodeEditor)[0];

+    var v_options = p_options;

+    var v_callback_onDataChanged;

+

+    var v_editor;

+    var v_editorDiv;

+    var v_name = "";

+    var v_enabled = true;

+    if (v_options.headerText != undefined) {

+        v_name = v_options.headerText;

+    }

+

+    var v_this = this;

+

+    this.EDITOROPTIONS = {

+        lineNumbers: true,

+        smartIndent: true,

+        indentUnit: 4,

+        lineWrapping: false,

+        foldGutter: true,

+        gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],

+        matchBrackets: true,

+        autoCloseBrackets: true,

+        highlightSelectionMatches: true,

+        styleActiveLine: true,

+        readOnly: v_options.readOnly

+    };

+

+    this.isValid = function() {

+        return true;

+    };

+

+    this.format = function(text) {

+        return text;

+    };

+

+    this.applicationCreated = function() {

+        createHtml();

+        setupCallbacks();

+        open();

+    };

+

+    this.onDataChanged = function(callback) {

+        v_callback_onDataChanged = callback;

+    }

+

+    function createHtml() {

+        $("#" + v_parentId).append('<div id="' + v_viewId + '" class="CodeEditor"></div>');

+        v_editorDiv = $("#" + v_viewId);

+        v_editorDiv.append(

+            '<div id="' + v_viewId + '_Header" class="CodeEditor_Header">' +

+                '<h3>' + v_name + '</h3>' +

+                '<button id="' + v_viewId + '_Format" class="CodeEditor_Format">Format</button>' +

+                '<button id="' + v_viewId + '_Save" class="CodeEditor_Save">Save</button>' +

+                '<button id="' + v_viewId + '_Close" class="CodeEditor_Close">X</button>' +

+            '</div>' +

+            '<div id="' + v_viewId + '_Editor" class="CodeEditor_Editor"></div>'

+        );

+        v_editor = new CodeMirror(document.getElementById(v_viewId + "_Editor"), v_this.EDITOROPTIONS);

+

+        if (!v_options.closeable) {

+            $('#' + v_viewId + '_Close').hide();

+        }

+

+        if (!v_options.formatAllowed) {

+            $('#' + v_viewId + '_Format').hide();

+        }

+

+        if (!v_options.manualSaveRequired) {

+            $('#' + v_viewId + '_Save').hide();

+        }

+

+        v_editor.setSize("100%", "100%");

+    }

+

+    function onChanges() {

+        var currentValue = v_editor.getValue();

+        if (v_callback_onDataChanged) {

+            var newValue = v_callback_onDataChanged(currentValue);

+            if (currentValue !== newValue) {

+                currentValue = newValue;

+                v_editor.setValue(currentValue);

+                return;

+            }

+        }

+        var isValidJSON = v_this.isValid(currentValue);

+        refreshBorder(isValidJSON);

+        if (!v_options.manualSaveRequired && isValidJSON) {

+            v_viewmodel.setTextData(currentValue);

+        }

+    }

+

+    function setupCallbacks() {

+        v_editor.on('changes', onChanges);

+        v_editor.on('focus', function() {

+            v_editorDiv.addClass('EditorFocused')

+            if (v_options.disableRefreshOnFocus){

+                v_enabled = false;

+            }

+        });

+        v_editor.on('blur', function() {

+            v_editorDiv.removeClass('EditorFocused')

+            v_enabled = true;

+        });

+

+        if (v_options.formatAllowed) {

+            $("#" + v_viewId + "_Format").click(function() {

+                if (v_this.isValid(v_editor.getValue())) {

+                    v_editor.setValue(v_this.format(v_editor.getValue()));

+                }

+            });

+        }

+

+        if (v_options.manualSaveRequired) {

+            $("#" + v_viewId + "_Save").click(function() {

+                v_viewmodel.setTextData(v_editor.getValue());

+            });

+        }

+

+        if (v_options.closeable) {

+            $("#" + v_viewId + "_Close").click(function() {

+                v_editorDiv.remove();

+            });

+        }

+

+        if (v_options.draggable) {

+            var handle = $("#" + v_viewId + "_Header");

+            handle.css("cursor", "move");

+            v_editorDiv.css("position", "absolute");

+

+            v_editorDiv.draggable({

+                containment: [$("#" + v_parentId).offset().left, $("#" + v_parentId).offset().top, 20000, 20000],

+                scroll: true,

+                handle: handle

+                }).resizable({

+                handles: "se",

+                resize: function() {}

+            });

+

+            v_editorDiv.on({

+                dragstop: function(event) {

+                    v_editor.focus();

+                },

+                click: function(event) {

+                    v_editor.focus();

+                },

+                keydown: function(event) {

+                    if (event.keyCode == 27) {

+                        v_editorDiv.remove();

+                    }

+                    event.stopPropagation();

+                }

+            });

+        }

+    }

+

+    function changeEditor(text, color, border) {

+        $("#" + v_viewId + "_Header > label").text(text);

+        $("#" + v_viewId + "_Header").css("color", color);

+        $("#" + v_viewId).css("border-color", border);

+    }

+

+    function open() {

+        changeEditor(v_name, "black", "#DDDDDD");

+

+        if (v_options.draggable && v_options.offset != undefined) {

+            v_editorDiv.offset(v_options.offset);

+            // in IE and chrome we need to set the offset twice so it gets calculated correctly

+            v_editorDiv.offset(v_options.offset);

+        }

+

+        if (v_options.focusEditorOnOpen) {

+            v_editor.focus();

+        }

+    };

+

+    function refreshBorder(valid) {

+        if (!valid) {

+            changeEditor("INVALID DATA: " + v_name, "red", "red");

+        } else {

+            changeEditor(v_name, "black", "#DDDDDD");

+        }

+    }

+

+    this.refresh = function(p_fullRefresh) {

+        function valueArrived(value) {

+            var scrollInfo = v_editor.getScrollInfo();

+            v_editor.off('changes', onChanges);

+            v_editor.setValue(value);

+            v_editor.on('changes', onChanges);

+            v_editor.scrollTo(scrollInfo.left, scrollInfo.top);

+            refreshBorder(v_this.isValid(value));

+        }

+

+        if (v_enabled && (p_fullRefresh || v_options.alwaysRefresh)) {

+            v_viewmodel.getTextData(valueArrived);

+        }

+    };

+}

+

+function CView_JSONCodeEditor(p_viewmodels, p_mainId, p_parentId, p_options) {

+    "use strict";

+    var editor = new CView_BaseCodeEditor(p_viewmodels, p_mainId, p_parentId, p_options);

+

+    editor.EDITOROPTIONS.mode = "javascript";

+

+    editor.format = function(text) {

+        var rawData = JSON.parse(text);

+        var formattedText = JSON.stringify(rawData, null, 4);

+        return formattedText;

+    };

+

+    editor.isValid = function(text) {

+        try {

+            JSON.parse(text);

+            return true;

+        } catch (e) {

+            return false;

+        }

+    };

+

+    return editor;

+}

+

+function CView_HtmlEditor(p_viewmodels, p_mainId, p_parentId, p_options) {

+    "use strict";

+    var editor = new CView_BaseCodeEditor(p_viewmodels, p_mainId, p_parentId, p_options);

+

+    editor.EDITOROPTIONS.mode = "xml";

+

+    editor.format = function(text) {

+        var parser = new DOMParser();

+        var doc = parser.parseFromString('<DIV>' + text + '</DIV>', "text/xml");

+        return doc.documentElement.innerHTML;

+    };

+

+    editor.isValid = function(text) {

+        function hasUniqueIds(doc) {

+            var result = true;

+            var elements_with_id = doc.querySelectorAll("*[id]");

+            for (var i = 0; result && (i < elements_with_id.length); i++) {

+                if (!/\S/.test(elements_with_id[i].getAttribute("id"))) { // There is an ID that is empty.

+                    return false;

+                }

+                for (var j = i+1; result && (j < elements_with_id.length); j++) {

+                    result = (elements_with_id[i].getAttribute("id") !== elements_with_id[j].getAttribute("id"));

+                }

+            }

+            return result;

+        }

+

+        try {

+            var parser = new DOMParser();

+            var doc = parser.parseFromString('<DIV>' + text + '</DIV>', "text/xml");

+            return hasUniqueIds(doc) && doc.getElementsByTagName("parsererror").length === 0;

+        } catch (e) {

+            return false;

+        }

+    };

+

+    return editor;

+}

+

+function CView_CssEditor(p_viewmodels, p_mainId, p_parentId, p_options) {

+    "use strict";

+    var editor = new CView_BaseCodeEditor(p_viewmodels, p_mainId, p_parentId, p_options);

+    editor.EDITOROPTIONS.mode = "css";

+    return editor;

+}

+

+function CView_JavascriptEditor(p_viewmodels, p_mainId, p_parentId, p_options) {

+    "use strict";

+    var editor = new CView_BaseCodeEditor(p_viewmodels, p_mainId, p_parentId, p_options);

+    editor.EDITOROPTIONS.mode = "javascript";

+    return editor;

+}

+

+//# sourceURL=WebApplicationFramework\Views\View_CodeEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_ComboBox.css b/htdocs/WebApplicationFramework/Views/View_ComboBox.css
new file mode 100644
index 0000000..bd4ce9d
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ComboBox.css
@@ -0,0 +1,25 @@
+.BasicComboBox {
+    font-family: "Arial";
+    vertical-align: middle;
+    height: 100%;
+    box-sizing: border-box;
+}
+
+.BasicComboBox > DIV {
+    width: 0px;
+    height: 25px;
+    display: inline-block;
+    vertical-align: middle;
+}
+
+.BasicComboBox > SELECT {
+    vertical-align: middle;
+    margin-right: 5px;
+    display: inline-block;
+}
+
+.BasicComboBox > LABEL {
+    vertical-align: middle;
+    margin-right: 5px;
+    display: inline-block;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_ComboBox.js b/htdocs/WebApplicationFramework/Views/View_ComboBox.js
new file mode 100644
index 0000000..0484698
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ComboBox.js
@@ -0,0 +1,191 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_ComboBox(p_viewmodels, p_mainId, p_parentId, p_data) {

+    "use strict";

+

+    /** constructor */

+

+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_ComboBox)[0];

+    var v_conditionViewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_ComboBox)[1];

+    var v_mainId = p_mainId;

+    var v_parentId = p_parentId;

+    var v_customData = p_data;

+    var v_selected = false;

+    var v_current = '';

+    var v_target;

+

+    var v_this = this;

+

+    var LIST = 1,

+    TARGET = 0;

+

+    var v_label;

+    var v_showLabel = v_customData.showLabel ? v_customData.showLabel : false;

+    var v_defaultValue = v_customData.defaultValue;

+

+    /** public functions */

+

+    this.applicationCreated = function () {

+        if (v_viewmodel != undefined) {

+            $("#" + v_parentId).append(getHtml());

+            if (v_customData.isElementLabelPresent) {

+                v_label = ViewUtils.addLabel(v_mainId, v_customData.elementText);

+            }

+            $("#" + v_mainId).addClass("BasicComboBox");

+

+            $("#" + v_mainId + "_cbValue").on({

+                'focus' : function () {

+                    v_selected = true;

+                },

+                'blur' : function (event) {

+                    v_selected = false;

+                },

+                'change' : function (event) {

+                    var obj = $(this);

+                    var val = obj.val();

+                    v_viewmodel.setValue(TARGET, obj.val());

+                    obj.blur();

+                }

+            });

+            

+            ViewUtils.addTooltip(v_mainId, v_customData);

+        }

+    };

+

+    this.refresh = function (p_fullRefresh) {

+        if (v_viewmodel != undefined && ViewUtils.checkVisibility(v_conditionViewmodel, v_mainId)) {

+            var dataObject = v_viewmodel.getListWithElementInfo();

+            if (dataObject == undefined || dataObject.values[0] == undefined) {

+                return;

+            }

+            

+            if (p_fullRefresh && v_customData.isElementLabelPresent && v_customData.elementText == undefined) {

+                v_label.text(dataObject.values[0].element);

+            }

+            

+            if (!v_selected) {

+                var element = "";

+                var jQcb = $("#" + v_mainId + "_cbValue");

+                

+                jQcb.empty();

+

+                v_current = dataObject.values[TARGET].val;

+                element = dataObject.values[TARGET].element;

+                

+                if (v_current == undefined) {

+                    $("#" + v_mainId + " > *").css("display", "none");

+                    $("#" + v_mainId).addClass("NoData");

+                } else {

+                    $("#" + v_mainId + " > *").css("display", "");

+                    $("#" + v_mainId).removeClass("NoData");

+                }

+                

+                var selectedFound = false;

+                if (v_customData.possibleValues == undefined && dataObject.values[LIST]) {

+                    if (dataObject.values[LIST].val && dataObject.values[LIST].val.constructor == Array) {

+                        for (var idx in dataObject.values[LIST].val) {

+                            if (dataObject.values[LIST].val.hasOwnProperty(idx)) {

+                                var vv = dataObject.values[LIST].val[idx];

+                                jQcb.append('<option value="' + vv + '"' + (v_current === vv ? ' selected="selected"' : '') + '>' + vv + '</option>');

+                                if (v_current === vv) {

+                                    selectedFound = true;

+                                }

+                            }

+                        }

+                    }

+                } else if (v_customData.possibleValues != undefined) {

+                    for (var i = 0; i < v_customData.possibleValues.length; ++i) {

+                        var vv = v_customData.possibleValues[i];

+                        jQcb.append('<option value="' + vv + '"' + (v_current === vv ? ' selected="selected"' : '') + '>' + vv + '</option>');

+                        if (v_current === vv) {

+                            selectedFound = true;

+                        }

+                    }

+                }

+                

+                if (v_defaultValue != undefined) {

+                    jQcb.prepend('<option value="' + v_defaultValue + '"' + (selectedFound ? '' : ' selected="selected"') + '>' + v_defaultValue + '</option>');

+                }

+                    

+                if (v_showLabel) {

+                    document.getElementById(v_mainId + "_cbHeader").value = ((v_customData.text) ? v_customData.text : element);

+                }

+                

+                if (v_customData.disabled !== true && dataObject.values[TARGET] != undefined && dataObject.values[TARGET].isWritable) {

+                    $("#" + v_mainId + " > select").prop('disabled', false);

+                } else {

+                    $("#" + v_mainId + " > select").prop('disabled', true);

+                }

+            }

+        }

+    };

+

+    /** private functions */

+

+    function getHtml() {

+        return '<div id="' + v_mainId + '"><div></div>' + (v_showLabel ? '<label id="' + v_mainId + '_cbHeader"></label>' : '') +

+        '<select id="' + v_mainId + '_cbValue"' + ((v_customData.writable !== "false") ? '' : ' disabled') + '></select></div>';

+    }

+}

+

+CView_ComboBox.getHelp = function() {

+    return "A combo box view that needs an element to set and either a second data connection in the viewmodel or a static list of choices.";

+}

+

+CView_ComboBox.expectsInterface = function() {

+    return [

+        {

+            "mandatory": ["setValue", "getListWithElementInfo"]

+        },

+        {

+            "optional": ["getState"]

+        }

+    ];

+};

+

+CView_ComboBox.getCustomDataSchema = function() {

+    var schema = {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "title": "Custom data for CView_ComboBox",

+        "type": "object",

+        "properties": {

+            "showLabel": {

+                "description": "Show label next to the combo box (default false).",

+                "type": "boolean",

+                "format": "checkbox",

+                "default": true

+            },

+            "text": {

+                "description": "The text of the label next to the combo box.",

+                "type": "string"

+            },

+            "possibleValues": {

+                "description": "A list of possible predefined values. If the list is undefined, the list from the viewmodel will be used.",

+                "type": "array",

+                "format": "table",

+                "items": {

+                    "type": "string",

+                    "title": "value"

+                }

+            },

+            "defaultValue": {

+                "description": "A default value that appears as the first element and is selected when the response does not match any element from the list.",

+                "type": "string"

+            },

+            "writable": {

+                "type": "boolean",

+                "format": "checkbox",

+                "description": "Whether we allow the data to be changed (default true).",

+                "default": false

+            }

+        },

+        "additionalProperties": false

+    };

+    $.extend(true, schema, ViewUtils.commonViewSchema, ViewUtils.commonElementSchema);

+    return schema;

+}

+

+//# sourceURL=WebApplicationFramework\Views\View_ComboBox.js

diff --git a/htdocs/WebApplicationFramework/Views/View_ComboButton.css b/htdocs/WebApplicationFramework/Views/View_ComboButton.css
new file mode 100644
index 0000000..2918350
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ComboButton.css
@@ -0,0 +1,59 @@
+.ComboButton {
+    box-sizing: border-box;
+    position: relative;
+}
+
+.ComboButton > BUTTON {
+    font-family: "Arial";
+    /*font-size:11px;*/
+    font-weight: bold;
+    color: #333333;
+    outline: none;
+    background-image: linear-gradient(to bottom, #FFFFFF, #e2e1e1);
+	text-align: center;
+    vertical-align: middle;
+    height: 25px;
+    overflow: hidden;
+    display: inline-block;
+    cursor: pointer;
+}
+
+.ComboButton > BUTTON:hover,
+.ComboButton > DIV:hover {
+    color: #58585a;
+    background-image: linear-gradient(to bottom,#e2e1e1, #FFFFFF);
+}
+
+.ComboButton > BUTTON:disabled {
+    color: #999999;
+    background-color: #AAAAAA;
+}
+
+.ComboButton > BUTTON SPAN {
+	display: inline-block; /* If you remove this, the SPAN that encloses the IMG will not be the same height. Which is most likely a problem. */
+}
+
+.ComboButton > BUTTON IMG {
+    height: 16px;
+    width: 16px;
+	vertical-align: middle; /* If you remove this, the IMG will be centered and the text will valign to baseline. */
+	margin-right: 5px; /* Distance between image and text */
+}
+
+.ComboButton > BUTTON LABEL {
+	vertical-align: middle;
+	margin-right: 5px;
+}
+
+.ComboButton > DIV {
+    vertical-align: middle;
+    display: inline-block;
+    text-align: center;
+    cursor: pointer;
+    background: rgba(0,0,0,0);
+    right: 5%;
+    bottom: 15%;
+    width: 10%;
+    height: 50%;
+    position: absolute;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_ComboButton.js b/htdocs/WebApplicationFramework/Views/View_ComboButton.js
new file mode 100644
index 0000000..1104ad9
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ComboButton.js
@@ -0,0 +1,107 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_ComboButton(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+
+    /** constructor */
+
+    var v_id = p_mainId;
+    var v_parentId = p_parentId;
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_ComboButton)[0];
+    var v_data = p_data;
+    if (v_data["class"] == undefined) {
+        v_data["class"] = "ComboButton";
+    }
+
+    var v_counter = 0;
+
+    var base = new CView_BasicButton(p_viewmodels, p_mainId, p_parentId, p_data);
+
+    this.applicationCreated = function() {
+        base.applicationCreated();
+        if (v_viewmodel != undefined) {
+            $("#" + v_id).append('<div><img src="WebApplicationFramework/Res/arrowDown.png"></div>');
+        }
+
+        $("#" + v_id + " > div").click(function(event) {
+            event.stopPropagation();
+            event.preventDefault();
+
+            var data = v_viewmodel.getList().values[1];
+            if (data == undefined || data.length == 0) {
+                return;
+            }
+
+            var customDataForMenu = {
+                "offset": {top: event.clientY - 10, left: event.clientX - 290}
+            };
+            var id = v_id + "_ContextMenu";
+            var contextMenu = new CView_ContextMenu([{
+                "getMenuElements": function() {
+                    var toReturn = [];
+                    var data = v_viewmodel.getList().values[1];
+                    if (data != undefined) {
+                        for (var i = 0; i < data.length; ++i) {
+                            var clicker = new ContextMenuItemClicker(i);
+                            toReturn.push({
+                                "text": data[i][0],
+                                "callback": clicker.click
+                            })
+                        }
+                    }
+                    return toReturn;
+                }
+            }], id, "TSGuiFrameworkMain", customDataForMenu);
+            contextMenu.applicationCreated();
+            ViewUtils.applyCss(customDataForMenu, id);
+        });
+
+        $("#" + v_id).hover(function() {
+            var data = v_viewmodel.getList();
+            $("#" + v_id).prop("title", data.values[1][data.selections[0][0]][0]);
+        });
+    };
+
+    this.refresh = function(fullRefresh) {
+        base.refresh(fullRefresh);
+        if (v_counter > 0) {
+            --v_counter;
+            if (v_counter == 0) {
+                base.onClick();
+            }
+        }
+    }
+
+    function ContextMenuItemClicker(p_index) {
+        var index = p_index;
+
+        this.click = function() {
+            v_viewmodel.select(index);
+            v_counter = 2;
+        }
+    }
+}
+
+CView_ComboButton.getHelp = function() {
+    return "A button view combined with a combo box.";
+};
+
+CView_ComboButton.expectsInterface = function() {
+    return [
+        {
+            "mandatory": ["setValue", "getListWithElementInfo", "select"]
+        },
+        {
+            "optional": ["getState"]
+        }
+    ];
+};
+
+CView_ComboButton.getCustomDataSchema = function() {
+    return CView_BasicButton.getCustomDataSchema();
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_ComboButton.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Condition.js b/htdocs/WebApplicationFramework/Views/View_Condition.js
new file mode 100644
index 0000000..eaf8375
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Condition.js
@@ -0,0 +1,81 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_Condition(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+    
+    /** constructor */
+    
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_Condition)[0];
+    var v_mainId = p_mainId;
+    var v_parentId = p_parentId;
+    var v_customData = p_data;
+    
+    var v_elements;
+    var v_prevState = 0;
+    
+    var v_this = this;
+    
+    /** public functions */
+
+    this.applicationCreated = function() {
+        $("#" + v_parentId).append(getHtml());
+        v_elements = $('#' + v_mainId + ' > div');
+        v_elements.css("display", "none");
+        v_prevState = -1;
+        $(v_elements[0]).css("display", "block");
+    };
+
+    this.refresh = function(p_fullRefresh) {
+        var state = v_viewmodel.getState();
+        if (state != v_prevState) {
+            v_elements.css("display", "none");
+            if (state) {
+                $(v_elements[0]).css("display", "block");
+            } else {
+                $(v_elements[1]).css("display", "block");
+            }
+            v_prevState = state;
+        }
+    };
+
+    /** private functions */
+    
+    function getHtml() {
+        var html = '<div id="' + v_mainId + '">';
+        for (var i = 0; i < v_customData.idsCreating.length; ++i) {
+            html += '<div id="' + v_customData.idsCreating[i] + '"></div>'
+        }
+        html += '</div>';
+        return html;
+    }
+}
+
+CView_Condition.getHelp = function() {
+    return "A view that only shows one of its connected child views based on the state of the connected viewmodel.";
+}
+
+CView_Condition.expectsInterface = function() {
+    return [
+        {
+            "mandatory": ["getState"]
+        }
+    ];
+}
+
+CView_Condition.getCustomDataSchema = function() {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CView_Condition",
+        "type": "object",
+        "properties": {},
+        "additionalProperties": false
+    };
+    
+    $.extend(true, schema, ViewUtils.commonViewSchema);
+    return schema;
+}
+
+//# sourceURL=WebApplicationFramework\Views\View_Condition.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_ContextMenu.css b/htdocs/WebApplicationFramework/Views/View_ContextMenu.css
new file mode 100644
index 0000000..923f171
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ContextMenu.css
@@ -0,0 +1,24 @@
+ul.ContextMenu {
+    list-style-type: none;
+    margin: 0;
+    padding: 0;
+    width: 300px;
+    position: absolute;
+    z-index: 9999;
+    max-height: 600px;
+    overflow: auto;
+}
+
+ul.ContextMenu li {
+    display: block;
+    color: #000;
+    background-color: #c5c5c5;
+    padding: 6px 0 6px 6px;
+    text-decoration: none;
+    cursor:pointer;
+}
+
+ul.ContextMenu li:hover {
+    background-color: #999;
+    color: white;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_ContextMenu.js b/htdocs/WebApplicationFramework/Views/View_ContextMenu.js
new file mode 100644
index 0000000..aa5898c
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ContextMenu.js
@@ -0,0 +1,80 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_ContextMenu(p_viewmodels, p_viewId, p_parentId, p_options) {
+    "use strict";
+    
+    var v_parentId = p_parentId;
+    var v_viewId = p_viewId;
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_ContextMenu)[0];
+    var v_options = p_options;
+    
+    var currentList;
+
+    function close() {
+        $("#" + v_viewId).remove();
+    }
+    
+    this.applicationCreated = function() {
+        currentList = v_viewmodel.getMenuElements();
+        $("#" + v_parentId).append('<ul class="ContextMenu" id="' + v_viewId + '"></ul>');
+        var ul = $("#" + v_viewId);
+        for (var i = 0; i < currentList.length; ++i) {
+            ul.append('<li>' + currentList[i].text + '</li>');
+        }
+        var elements = ul.find("li");
+        for (var i = 0; i < elements.length; ++i) {
+            $(elements[i]).click(function() {
+                currentList[$(this).index()].callback();
+                close();
+            });
+        }
+        
+        if (v_options.offset != undefined) {
+            ul.offset(v_options.offset);
+            ul.offset(v_options.offset);
+        }
+        
+        ul.mouseleave(close);
+    }
+}
+
+CView_ContextMenu.getHelp = function() {
+    return "A context menu view that closes when the mouse leaves it.";
+};
+
+CView_ContextMenu.expectsInterface = function() {
+    return [
+        {
+            "mandatory": ["getMenuElements"]
+        }
+    ];
+};
+
+CView_ContextMenu.getCustomDataSchema = function() {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CView_ContextMenu",
+        "type": "object",
+        "properties": {
+            "offset": {
+                "description": "The offset of the context menu.",
+                "type": "object",
+                "properties": {
+                    "top": {
+                        "type": "integer"
+                    },
+                    "left": {
+                        "type": "integer"
+                    }
+                }
+            }
+        },
+        "additionalProperties": false
+    };
+    return schema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_ContextMenu.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Div.js b/htdocs/WebApplicationFramework/Views/View_Div.js
new file mode 100644
index 0000000..9cd3c4c
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Div.js
@@ -0,0 +1,93 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_Div(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+    
+    /** constructor */
+    
+    var v_mainId = p_mainId;
+    var v_parentId = p_parentId;
+    var v_customData = p_data;
+    if (v_customData.text == undefined) {
+        v_customData.text = "";
+    }
+    
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_Div)[0];
+    var v_conditionViewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_Div)[1];
+    
+    var v_currentHtml;
+    
+    var v_this = this;
+    
+    /** public functions */
+
+    this.applicationCreated = function() {
+        $("#" + v_parentId).append(getHtml());
+        if (v_customData.isElementLabelPresent) {
+            ViewUtils.addLabel(v_mainId, v_customData.elementText);
+        }
+        if (v_customData.class != undefined) {
+            $("#" + v_mainId).addClass(v_customData.class);
+        }
+        
+        var v_currentHtml = v_customData.text;
+    };
+
+    this.refresh = function() {
+        if (ViewUtils.checkVisibility(v_conditionViewmodel, v_mainId)) {
+            if (v_viewmodel != undefined) {
+                var html = v_viewmodel.getHtml();
+                if (html != v_currentHtml) {
+                    $("#" + v_mainId).html(html);
+                    v_currentHtml = html;
+                }
+            }
+        }
+    };
+
+    /** private functions */
+    
+    function getHtml() {
+        return '<div id="' + v_mainId + '">' + v_customData.text + '</div>';
+    }
+}
+
+CView_Div.getHelp = function() {
+    return "A single div element. Any kind of html can be inserted by using the text member of the custom data.";
+}
+
+CView_Div.expectsInterface = function() {
+    return [
+        {
+            "optional": ["getHtml"]
+        },
+        {
+            "optional": ["getState"]
+        }
+    ];
+};
+
+CView_Div.getCustomDataSchema = function() {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CView_Div",
+        "type": "object",
+        "properties": {
+            "class": {
+                "type": "string",
+                "description": "the css class of the div"
+            },
+            "text": {
+                "type": "string",
+                "description": "the text of the div"
+            }
+        },
+        "additionalProperties": false
+    };
+    $.extend(true, schema, ViewUtils.commonViewSchema, ViewUtils.commonElementLabelSchema);
+    return schema;
+};
+//# sourceURL=WebApplicationFramework\Views\View_Div.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_ElementAligner.js b/htdocs/WebApplicationFramework/Views/View_ElementAligner.js
new file mode 100644
index 0000000..e35872c
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ElementAligner.js
@@ -0,0 +1,187 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_ElementAligner(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+
+    /** constructor */
+
+    var v_mainId = p_mainId;
+    var v_parentId = p_parentId;
+    var v_customData = p_data;
+
+    var v_viewmodels = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_ElementAligner);
+    var v_dataViewmodel = v_viewmodels[0];
+    var v_flexViewmodel = v_viewmodels[1];
+    var v_conditionViewmodel = v_viewmodels[2];
+
+    var v_aligner;
+    var v_subViews = [];
+    var v_currentListWithElementInfo;
+
+    var v_this = this;
+
+    /** public functions */
+
+    this.applicationCreated = function() {
+        createSubViews();
+    };
+
+    this.refresh = function(p_fullRefresh) {
+        if (ViewUtils.checkVisibility(v_conditionViewmodel, v_mainId)) {
+            if (v_dataViewmodel != undefined) {
+                v_currentListWithElementInfo = v_dataViewmodel.getListWithElementInfo();
+            }
+            for (var i = 0; i < v_subViews.length; ++i) {
+                if (v_subViews[i] != undefined && v_subViews[i].refresh != undefined) {
+                    v_subViews[i].refresh(p_fullRefresh);
+                }
+            }
+        }
+    };
+
+    /** private functions */
+
+    function getAligner() {
+        var aligner = new CView_Aligner(p_viewmodels, v_mainId, v_parentId, v_customData);
+        if (v_customData.flexCalculation || v_customData.resizable) {
+            aligner.getLenghtsFromViewmodel = getLenghtsFromViewmodel;
+        }
+        return aligner;
+    }
+
+    function getLenghtsFromViewmodel() {
+        if (v_flexViewmodel != undefined && v_flexViewmodel.getChildPercentagesFromFlex != undefined) {
+            var flexes = [];
+            var total = 0;
+            var subviews = v_customData.subviews;
+            for (var i = 0; i < subviews.length; ++i) {
+                if (subviews[i].flex != undefined) {
+                    flexes.push(subviews[i].flex);
+                    total += subviews[i].flex;
+                } else {
+                    flexes.push(1);
+                    total += 1;
+                }
+            }
+            v_flexViewmodel.getChildPercentagesFromFlex(flexes, total);
+            return flexes;
+        } else {
+            return undefined;
+        }
+    }
+
+    function createSubViews() {
+
+        v_customData.idsCreating = [];
+        var viewData = [];
+
+        var subViewDescriptors = v_customData.subviews;
+        for (var i = 0; i < subViewDescriptors.length; ++i) {
+            if (subViewDescriptors[i].subView != undefined && window[subViewDescriptors[i].subView] != undefined) {
+                var parentId = v_mainId + "_SubView_" + i;
+                var viewId = v_mainId + "_SubView_" + i + "_View";
+                v_customData.idsCreating.push(parentId);
+                viewData[i] = {
+                    "parentId": parentId,
+                    "viewId": v_mainId + "_SubView_" + i + "_View",
+                    "customData": subViewDescriptors[i]
+                };
+            } else {
+                alert(subViewDescriptors[i].subView + " is not a valid view");
+            }
+        }
+
+        v_aligner = getAligner();
+        v_aligner.applicationCreated();
+
+        for (var i = 0; i < viewData.length; ++i) {
+            if (viewData[i] != undefined) {
+                var viewmodels = [];
+                if (v_dataViewmodel != undefined) {
+                    viewmodels = [new ViewmodelProxy(i)];
+                }
+                var subView = new window[viewData[i].customData.subView](viewmodels, viewData[i].viewId, viewData[i].parentId, viewData[i].customData);
+                subView.applicationCreated();
+                ViewUtils.applyCss(viewData[i].customData, viewData[i].viewId);
+                ViewUtils.processCss(viewData[i].customData, viewData[i].parentId);
+
+                v_subViews[i] = subView;
+            }
+        }
+    }
+
+    function ViewmodelProxy(p_index) {
+
+        var v_index = p_index;
+
+        this.select = v_dataViewmodel.select;
+
+        this.getList = function() {
+            return {
+                "selections": v_currentListWithElementInfo.selections,
+                "values": [[v_currentListWithElementInfo.values[v_index].val, undefined, v_currentListWithElementInfo.values[v_index].isWritable]]
+            };
+        };
+
+        this.getListWithElementInfo = function() {
+            return {
+                "selections": v_currentListWithElementInfo.selections,
+                "values": [v_currentListWithElementInfo.values[v_index]]
+            };
+        };
+
+        this.setValue = function(aDataPathIndex, aValue, aIndexInList, p_lastSelectionIndexes, p_callback, p_additionalData) {
+            v_dataViewmodel.setValue(v_index, aValue, aIndexInList, p_callback, p_additionalData);
+        };
+
+        this.getDataList = v_dataViewmodel.getDataList;
+    }
+}
+
+CView_ElementAligner.getHelp = function() {
+    return "An aligner that creates its subviews specified in the custom data. See CView_Aligner.";
+};
+
+CView_ElementAligner.expectsInterface = function() {
+    var expectedInterface = CView_Aligner.expectsInterface();
+    expectedInterface.unshift({
+        "optional": ["getState"]
+    });
+    expectedInterface.unshift({
+        "optional": ["getChildPercentagesFromFlex"]
+    });
+    expectedInterface.unshift({
+        "optional": ["getListWithElementInfo", "setValue", "select"]
+    });
+    return expectedInterface;
+};
+
+CView_ElementAligner.getCustomDataSchema = function() {
+    var schema = CView_Aligner.getCustomDataSchema();
+    schema.title = "Custom data for CView_ElementAligner";
+    schema.properties.subviews = {
+        "type": "array",
+        "format": "tabs",
+        "description": "The subviews and their custom data",
+        "items": {
+            "type": "object",
+            "title": "subview",
+            "properties": {
+                "subView" : {
+                    "type" : "string",
+                    "description": "the class name of the subview"
+                }
+            },
+            "required": ["subView"],
+            "additionalProperties": true
+        },
+        "minItems": 1
+    }
+    schema.required = ["subviews"];
+    return schema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_ElementAligner.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_ElementTable.css b/htdocs/WebApplicationFramework/Views/View_ElementTable.css
new file mode 100644
index 0000000..b7ba67b
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ElementTable.css
@@ -0,0 +1,172 @@
+.ElementTable,
+.TableGray {
+    width: 100%;
+    height: 100%;
+    white-space: nowrap;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+}
+
+.ElementTable_HeaderBar,
+.TableGray_HeaderBar {
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+    width: 100%;
+    overflow: hidden;
+    padding-left: 2px;
+    white-space: nowrap;
+    border-bottom: 1px solid black;
+}
+
+.ElementTable_HeaderBar {
+    background-color: #55BAD4;
+}
+
+.TableGray_HeaderBar {
+    background-color: #888888;
+}
+
+.ElementTable_HeaderBar > *,
+.TableGray_HeaderBar > * {
+    display: inline-block;
+    vertical-align: middle;
+    overflow: hidden;
+    white-space: nowrap;
+}
+
+.ElementTable_Name,
+.TableGray_Name {
+    width: 50%;
+    font-weight: bold;
+}
+
+.ElementTable_SearchLabel,
+.TableGray_SearchLabel {
+    width: 15%;
+    text-align: right;
+}
+
+.ElementTable_SearchInput,
+.TableGray_SearchInput {
+    width: 35%;
+}
+
+.ElementTable_TableWrapper,
+.TableGray_TableWrapper {
+    overflow-y: auto;
+}
+
+.ElementTable table,
+.TableGray table {
+    width: 100%;
+}
+
+.ElementTable table tbody tr.ElementTable_Selected {
+    background-color: #66a19f;
+}
+
+.TableGray table tbody tr.TableGray_Selected {
+    background-color: #4CAF50;
+    color: white;
+}
+
+.ElementTable table,
+.TableGray table {
+    border: none;
+    border-collapse: collapse;
+}
+
+.ElementTable table tbody tr.ElementTable_Header,
+.TableGray table tbody tr.TableGray_Header {
+    border-bottom: 1px solid black;
+    color: black;
+    font-weight: bold;
+    /*font-size: 14px;*/
+    text-align: left;
+    padding: 2px;
+}
+
+.ElementTable table tbody tr.ElementTable_Header {
+    background-color: #66CBE5;
+}
+
+.TableGray table tbody tr.TableGray_Header {
+    background-color: #8D8D8D;
+}
+
+.ElementTable_Sort_No,
+.ElementTable_Sort_Asc,
+.ElementTable_Sort_Desc,
+.TableGray_Sort_No,
+.TableGray_Sort_Asc,
+.TableGray_Sort_Desc {
+    background-position: right center;
+    background-repeat: no-repeat;
+}
+.ElementTable_Sort_Asc,
+.TableGray_Sort_Asc {
+    background-image: url("WebApplicationFramework/Res/sort_asc.png");
+}
+.ElementTable_Sort_Desc,
+.TableGray_Sort_Desc {
+    background-image: url("WebApplicationFramework/Res/sort_desc.png");
+}
+.ElementTable_Sort_No,
+.TableGray_Sort_No {
+    background-image: url("WebApplicationFramework/Res/sort_both.png");
+}
+
+.ElementTable td,
+.ElementTable th,
+.TableGray th,
+.TableGray td {
+    padding: 2px 2px;
+}
+
+.ElementTable tr:nth-child(odd) {
+    background-color: #D4F0F8;
+    color: black;
+}
+
+.ElementTable tbody tr.ElementTable_Odd {
+    background-color: #D4F0F8;
+}
+
+.ElementTable tr:nth-child(even) {
+    background-color: #F2FBFD;
+    color: black;
+}
+
+.ElementTable tbody tr.ElementTable_Even {
+    background-color: #F2FBFD;
+}
+
+.ElementTable tbody tr:hover {
+    background-color: #0066b3;
+    color: white;
+}
+
+.TableGray tr:nth-child(odd) {
+    color: black;
+    background-color: #c5c5c5;
+}
+
+.TableGray tbody tr.TableGray_Odd {
+    background-color: #c5c5c5;
+}
+
+.TableGray tr:nth-child(even) {
+    color: black;
+    background-color: #c5c5c5;
+}
+
+.TableGray tbody tr.TableGray_Even {
+    background-color: #c5c5c5;
+}
+
+.TableGray tbody tr:hover {
+    background-color: #999;
+    color: white;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_ElementTable.js b/htdocs/WebApplicationFramework/Views/View_ElementTable.js
new file mode 100644
index 0000000..ce1d53e
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ElementTable.js
@@ -0,0 +1,235 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_ElementTable(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+    
+    /** constructor */
+    
+    if (p_data.class == undefined) {
+        p_data.class = "ElementTable";
+    }
+    
+    var base = new CView_Table_Vertical(p_viewmodels, p_mainId, p_parentId, p_data);
+    this.base = base;
+    
+    var v_flexViewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_ElementTable)[0];
+    
+    // temp variables for resizable behaviour
+    var lastObj;
+    var prevObjWidth;
+    var prevWidth;
+    var prevPosition;
+    
+    var v_this = this;
+
+    /** public functions */
+
+    this.applicationCreated = base.applicationCreated;
+    this.refresh = base.refresh;
+
+    /** overridden functions */
+
+    base.setSelection = function(selection) {
+        $("#" + base.tableId + " tbody tr").removeClass(base.mainClass + "_Selected");
+        if (selection != undefined) {
+            for (var i = 0; i < selection.length; ++i) {
+                $("#" + base.tableId + " tbody tr:nth-child(" + (selection[i] + 2) + ")").addClass(base.mainClass + "_Selected");
+            }
+        }
+    };
+
+    base.addDataToTable = function(p_numberOfRows, p_numberOfColumns) {
+        var numberOfRows = $("#" + base.tableId + " tbody tr").length;
+        if (p_numberOfRows > 0) {
+            // create the html for the row and add it to the DOM
+            var html = '';
+            for (var i = 0; i < p_numberOfRows; ++i) {
+                html += '<tr>';
+                for (var j = 0; j < p_numberOfColumns; ++j) {
+                    html += '<td id="' + base.tableId + "_SubView_" + (numberOfRows + i - 1) + "_" + j + '"></td>';
+                }
+                html += '</tr>'
+            }
+            $("#" + base.tableId).append(html);
+            
+            // create the subviews where applicable
+            for (var i = 0; i < p_numberOfRows; ++i) {
+                var subViews = [];
+                for (var j = 0; j < p_numberOfColumns; ++j) {
+                    if (base.subViewDescriptors != undefined && base.subViewDescriptors[j] != undefined && base.subViewDescriptors[j].subView != undefined && window[base.subViewDescriptors[j].subView] != undefined) {
+                        var parentId = base.tableId + "_SubView_" + (numberOfRows + i - 1) + "_" + j;
+                        var viewId = base.tableId + "_SubView_" + (numberOfRows + i - 1) + "_" + j + "_View";
+                        var viewmodel = new base.ViewmodelProxy(numberOfRows + i - 1, j);
+                        
+                        var subView = new window[base.subViewDescriptors[j].subView]([viewmodel], viewId, parentId, base.subViewDescriptors[j]);
+                        subView.applicationCreated();
+                        ViewUtils.applyCss(base.subViewDescriptors[j], viewId);
+                        ViewUtils.processCss(base.subViewDescriptors[j], parentId);
+                        subViews.push(subView);
+                    } else {
+                        // we must ensure that there are as many subviews as the number of cells in the table
+                        subViews.push(null);
+                    }
+                }
+                base.subViews.push(subViews);
+            }
+        } else {
+            // we remove the correct number of rows from the DOM and the subviews
+            $("#" + base.tableId + " tbody tr").slice(numberOfRows + p_numberOfRows).remove();
+            for (var i = 0; i > p_numberOfRows; --i) {
+                base.subViews.pop();
+            }
+        }
+    };
+
+    base.createHeader = function(p_headerList) {
+        var html = '<tr>'
+        for (var i = 0; i < p_headerList.length; ++i) {
+            html += '<th>' + p_headerList[i].heading + '</th>';
+        }
+        html += '</tr>'
+        $("#" + base.tableId).append(html);
+        var firstRow = $("#" + base.tableId + " tbody tr");
+        firstRow.addClass(base.mainClass + "_Header");
+        calculateWidthsFromFlex();
+        
+        if (base.customData.displayHeader === false) {
+            firstRow.css("display", "none");
+        } else {
+            if (base.customData.resizable === true) {
+                // Resizing only works if we give the widths in pixels
+                recalculateTableWidthPixels();
+                
+                var resizables = $("#" + base.tableId + " tbody tr th");
+                var lastObj = resizables.last();
+                for (var i = 0; i < resizables.length - 1; ++i) {
+                    $(resizables[i]).resizable({
+                        handles: "e",
+                        start: function(event, ui) {
+                            prevObjWidth = lastObj.width();
+                            prevWidth = ui.size.width;
+                            prevPosition = ui.originalElement.offset().left;
+                        },
+                        resize: function(event, ui) {
+                            // if our offset changes or the last column's width does not change any more
+                            if (ui.originalElement.offset().left != prevPosition || lastObj.width() == prevObjWidth) {
+                                ui.size.width = prevWidth; //do not resize
+                            } else {
+                                prevWidth = ui.size.width;
+                                prevObjWidth = lastObj.width();
+                            }
+                        }
+                    });
+                }
+            }
+        }
+        
+        if (base.customData.showToolTip !== false) {
+            $("#" + base.tableId).on("mouseenter", "td", function() {
+                var header = $("#" + base.tableId + " tbody tr th");
+                $(this).prop("title", $(header[$(this).index()]).text());
+            });
+        }
+    };
+    
+    base.createSeparators = function(separators) {
+        var rows = $("#" + base.tableId + " tbody tr");
+        var numberOfColumns = $("#" + base.tableId + " tbody tr th").length;
+        for (var i = 0; i < separators.length; ++i) {
+            if (separators[i].index + 1 < rows.length) {
+                var rowAfterSeparator = rows[separators[i].index + 1];
+                $(rowAfterSeparator).before('<div class="' + base.mainClass + '_Separator">' + separators[i].text + '</div>');
+            }
+        }
+    }
+
+    base.setupSelection = function() {
+        $("#" + base.tableId).on("click", "tr", function() {
+            var index = $(this).index() - 1;
+            if (index >= 0) {
+                base.dataViewmodel.select(base.getUnalteredIndex(index));
+            }
+        });
+    };
+    
+    base.displayFilter = function() {
+        return base.sortViewmodel != undefined && base.customData.filter !== false;
+    };
+    
+    base.displaySort = function() {
+        return base.sortViewmodel != undefined && base.customData.sort !== false;
+    };
+    
+    base.getIndexOfTableHeaderBasedOnOrientation = function(obj) {
+        return obj.index();
+    };
+
+    /** private functions */
+
+    function calculateWidthsFromFlex() {
+        if (v_flexViewmodel != undefined && base.subViewDescriptors != undefined) {
+            var cols = $("#" + base.mainId + " table tbody tr th");
+            var flexes = [];
+            var total = 0;
+            for (var i = 0; i < base.subViewDescriptors.length; ++i) {
+                if (base.subViewDescriptors[i].flex != undefined) {
+                    flexes.push(base.subViewDescriptors[i].flex);
+                    total += base.subViewDescriptors[i].flex;
+                } else {
+                    flexes.push(1);
+                    total += 1;
+                }
+            }
+            v_flexViewmodel.getChildPercentagesFromFlex(flexes, total);
+            var table = $("#" + base.tableId);
+            for (var i = cols.length - 1; i >= 0; --i) {
+                table.prepend('<col width=' + flexes[i] + '>');
+            }
+        }
+    }
+
+    function recalculateTableWidthPixels() {
+        var cols = $("#" + base.tableId + " tbody tr th");
+        for (var i = 0; i < cols.length - 1; ++i) {
+            $(cols[i]).width(cols[i].getBoundingClientRect().width);
+        }
+        $(cols[cols.length - 1]).removeAttr('style');
+    }
+}
+
+CView_ElementTable.getHelp = function() {
+    return "A table view whose columns can contain single element subviews.";
+}
+
+CView_ElementTable.expectsInterface = function() {
+    var expectedInterface = CView_Table_Vertical.expectsInterface();
+    expectedInterface.unshift({
+        "optional": ["getChildPercentagesFromFlex"]
+    });
+    return expectedInterface;
+}
+
+CView_ElementTable.getCustomDataSchema = function() {
+    var schema = CView_Table_Vertical.getCustomDataSchema();
+    schema.title = "Custom data for CView_ElementTable";
+    schema.properties.class.default = "ElementTable";
+    schema.properties.sort.default = false;
+    schema.properties.resizable = {
+        "description": "Whether we want the table to be resizable (default false). It will only work when no subviews are specified.",
+        "type": "boolean",
+        "format": "checkbox",
+        "default": true
+    };
+    schema.properties.showToolTip = {
+        "description": "Whether the column name is shown when hovering over a cell.",
+        "type": "boolean",
+        "format": "checkbox",
+        "default": false
+    };
+    return schema;
+}
+
+//# sourceURL=WebApplicationFramework\Views\View_ElementTable.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_ElementTableForLargeData.js b/htdocs/WebApplicationFramework/Views/View_ElementTableForLargeData.js
new file mode 100644
index 0000000..9f099b8
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ElementTableForLargeData.js
@@ -0,0 +1,109 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_ElementTableForLargeData(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+    
+    /** constructor */
+    
+    var base = new CView_ElementTable(p_viewmodels, p_mainId, p_parentId, p_data);
+    var v_scrollId = base.base.mainId + "_Scroll";
+    var scrollBar = new CView_Scroll(p_viewmodels, v_scrollId, base.base.tableWrapperId, p_data);
+    
+    var v_viewmodels = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_ElementTableForLargeData);
+    var v_streamingViewmodel = v_viewmodels[0];
+    var v_positionViewmodel = v_viewmodels[1];
+    var v_conditionViewmodel = v_viewmodels[2];
+    var v_scrollInitialised = false;
+    
+    /** public functions */
+
+    this.applicationCreated = function() {
+        base.applicationCreated();
+        $('#' + base.base.tableWrapperId).css("position", "relative");
+    };
+    
+    this.refresh = function(p_fullRefresh) {
+        if (ViewUtils.checkVisibility(v_conditionViewmodel, base.base.mainId)) {
+            var isStreaming = false;
+            if (v_streamingViewmodel.isStreaming != undefined) {
+                isStreaming = v_streamingViewmodel.isStreaming();
+            }
+            if (v_scrollInitialised && !isStreaming) {
+                $("#" + v_scrollId).remove();
+                v_scrollInitialised = false;
+                $("#" + base.base.tableWrapperId).scrollTop(0).css("overflow-y", "auto");
+            } else if (!v_scrollInitialised && isStreaming) {
+                scrollBar.applicationCreated();
+                v_scrollInitialised = true;
+                $("#" + base.base.tableWrapperId).scrollTop(0).css("overflow-y", "hidden");
+            }
+            
+            base.refresh(p_fullRefresh);
+            if (isStreaming) {
+                scrollBar.refresh(p_fullRefresh);
+            }
+            
+            var oddRows = $("#" + base.base.mainId + "." + base.base.mainClass + " tr:nth-child(odd)");
+            var evenRows = $("#" + base.base.mainId + "." + base.base.mainClass + " tr:nth-child(even)");
+            
+            if (isStreaming && v_positionViewmodel != undefined) {
+                if (v_positionViewmodel.getPosition() % 2 == 0) {
+                    oddRows.removeClass(base.base.mainClass + "_Even");
+                    oddRows.addClass(base.base.mainClass + "_Odd");
+                    evenRows.removeClass(base.base.mainClass + "_Odd");
+                    evenRows.addClass(base.base.mainClass + "_Even");
+                } else {
+                    evenRows.removeClass(base.base.mainClass + "_Even");
+                    evenRows.addClass(base.base.mainClass + "_Odd");
+                    oddRows.removeClass(base.base.mainClass + "_Odd");
+                    oddRows.addClass(base.base.mainClass + "_Even");
+                }
+            } else {
+                oddRows.removeClass(base.base.mainClass + "_Even");
+                oddRows.removeClass(base.base.mainClass + "_Odd");
+                evenRows.removeClass(base.base.mainClass + "_Odd");
+                evenRows.removeClass(base.base.mainClass + "_Even");
+            }
+        }
+    };
+}
+
+CView_ElementTableForLargeData.getHelp = function() {
+    return "A table view whose columns can contain single element subviews and can use viewmodels suited for handling larger datasets.";
+};
+
+CView_ElementTableForLargeData.expectsInterface = function() {
+    var expectedInterface = CView_ElementTable.expectsInterface();
+    var scrollExpectedInterface = CView_Scroll.expectsInterface();
+    for (var i = 0; i < scrollExpectedInterface.length; ++i) {
+        expectedInterface.push(scrollExpectedInterface[i]);
+    }
+    expectedInterface.unshift({
+        "optional": ["getState"]
+    });
+    expectedInterface.unshift({
+        "optional": ["getPosition"]
+    });
+    expectedInterface.unshift({
+        "optional": ["isStreaming"]
+    });
+    
+    return expectedInterface;
+};
+
+CView_ElementTableForLargeData.getCustomDataSchema = function() {
+    var tableSchema = CView_ElementTable.getCustomDataSchema();
+    var scrollSchema = CView_Scroll.getCustomDataSchema();
+    
+    for (var id in scrollSchema.properties) {
+        tableSchema.properties[id] = scrollSchema.properties[id];
+    }
+    
+    tableSchema.title = "Custom data for CView_ElementTableForLargeData";
+    return tableSchema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_ElementTableForLargeData.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_FileSelector.css b/htdocs/WebApplicationFramework/Views/View_FileSelector.css
new file mode 100644
index 0000000..676ac86
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_FileSelector.css
@@ -0,0 +1,125 @@
+DIV {
+    margin:0;
+    padding:0;
+}

+
+.FileSelector_List {
+    height: 250px;
+    overflow: auto;
+}
+
+.FileSelector BUTTON {
+    display: inline-block;
+}
+
+.FileSelector DIV.FileSelector_Bread {
+    display: inline-block;
+    background-color: #ddd;
+    border: thin solid #777;
+    padding: 2px;
+}

+
+.FileSelector DIV.FileSelector_TopBar {

+    border-bottom:thin solid #777;
+    padding: 2px;

+    margin: 10px;

+}
+
+.FileSelector DIV.FileSelector_BottomBar,
+.FileSelector DIV.FileSelector_ButtonBar {
+    border-top: thin solid #777;
+    padding: 2px;
+    margin: 10px;
+    height: 30px;
+    box-sizing: border-box;
+}
+
+.FileSelector_BottomBar LABEL {
+    display: inline-block;
+    width: 70px;
+    height: 20px;
+    vertical-align: middle;
+    box-sizing: border-box;
+}
+
+.FileSelector_Selection {
+    display: inline-block;
+    height: 20px;
+    resize: none;
+    width: calc(79% - 110px);
+    spellcheck: false;
+    vertical-align: middle;
+    box-sizing: border-box;
+}
+
+.FileSelector_Filters {
+    display: inline-block;
+    height: 20px;
+    width: 20%;
+    vertical-align: middle;
+    box-sizing: border-box;
+}
+
+.FileSelector_OkButton,
+.FileSelector_CancelButton {
+    display: inline-block;
+    height: 20px;
+    width: 40px;
+    vertical-align: middle;
+    box-sizing: border-box;
+    float: right;
+}
+
+.FileSelector_CancelButton {
+    width: 60px;
+}

+
+.FileSelector LI {

+    list-style-type: none;

+    padding-left: 20px;
+    
+    -moz-user-select     : none;
+    -khtml-user-select   : none;
+    -webkit-user-select  : none;
+    -o-user-select       : none;
+    user-select          : none;

+}
+
+.FileSelector_Selected {
+    background: #56F !important;
+}
+
+LI[filetype="-d"] {

+    background: url("/WebApplicationFramework/Res/d.png") no-repeat;

+}

+LI[filetype="-f"] {

+    background: url("/WebApplicationFramework/Res/f.png") no-repeat;

+}

+LI[filetype="ld"] {

+    background: url("/WebApplicationFramework/Res/ld.png") no-repeat;

+}

+LI[filetype="lf"] {

+    background: url("/WebApplicationFramework/Res/lf.png") no-repeat;

+}
+

+LI, LI SPAN {

+    cursor: pointer;

+}

+LI SPAN.FileSelector_Name {

+    font-family: Consolas, "Courier New", Courier, monospace;

+}

+LI SPAN.FileSelector_Size, LI SPAN.FileSelector_Time {

+    font-size: 80%;

+}

+LI SPAN.FileSelector_Size:before {

+    content: " [";

+}

+LI SPAN.FileSelector_Size:after {

+    content: "B] ";

+}

+LI SPAN.FileSelector_Time:before {

+    content: " @";

+}

+LI SPAN.FileSelector_Time:after {

+    content: " ";

+}

diff --git a/htdocs/WebApplicationFramework/Views/View_FileSelector.html b/htdocs/WebApplicationFramework/Views/View_FileSelector.html
new file mode 100644
index 0000000..ad8d3fe
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_FileSelector.html
@@ -0,0 +1,22 @@
+<style id="FileSelector_WebAppStyle" type="text/css"></style>
+<div class="FileSelector">
+    <div class="FileSelector_TopBar">
+        <button class="FileSelector_CreateDir">Create Directory</button>
+        <button class="FileSelector_Back">Back</button>
+        <button class="FileSelector_Forward">Forward</button>
+        <button class="FileSelector_Home">Home</button>
+        <div class="FileSelector_Bread"></div>
+    </div>
+    <div class="FileSelector_List">
+        <ul></ul>
+    </div>
+    <div class="FileSelector_BottomBar">
+        <label>Selection: </label>
+        <textarea class="FileSelector_Selection"></textarea>
+        <select class="FileSelector_Filters"></select>
+    </div>
+    <div class="FileSelector_ButtonBar">
+        <button class="FileSelector_CancelButton">Cancel</button>
+        <button class="FileSelector_OkButton">OK</button>
+    </div>
+</div>
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_FileSelector.js b/htdocs/WebApplicationFramework/Views/View_FileSelector.js
new file mode 100644
index 0000000..e47ef28
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_FileSelector.js
@@ -0,0 +1,224 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_FileSelector(p_viewmodels, p_mainId, p_parentId, p_options) {

+    "use strict";

+    

+    var HTML = "WebApplicationFramework/Views/View_FileSelector.html";

+    var v_parentId = p_parentId;

+    var v_mainId = p_mainId;

+    

+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_FileSelector)[0];

+    var v_customData = p_options;

+    

+    var v_this = this;

+    

+    this.applicationCreated = function() {

+        var mainDiv = document.createElement("div");

+        mainDiv.setAttribute("id", v_mainId);

+        $("#" + v_parentId).append(mainDiv);

+        

+        function htmlLoaded(ok, data) {

+            if (ok) {

+                $('#' + v_mainId).append(data);

+                

+                var select = $('#' + v_mainId + " .FileSelector_Filters");

+                var options = v_viewmodel.getFileTypeList();

+                for (var i = 0; i < options.length; ++i) {

+                    select.append(new Option(options[i].text, options[i].value));

+                }

+                select.change(function() {

+                    v_viewmodel.setFilter($('#' + v_mainId + " .FileSelector_Filters option:selected").text(), refresh);

+                });

+                

+                setupCallbacks();

+                v_viewmodel.home(refresh);

+                

+            } else {

+                alert("Error loading html file: " + HTML);

+            }

+        }

+        

+        v_viewmodel.loadFile(HTML, htmlLoaded);

+    };

+    

+    function refresh(fullRefreshView) {

+        if (fullRefreshView) {

+            fullRefresh();

+        } else {

+            selectionRefresh();

+        }

+    }

+    

+    function fullRefresh() {

+        var path = v_viewmodel.getCurrentDir();

+        $('#' + v_mainId).find(".FileSelector_Bread").text(path);

+        

+        var files = v_viewmodel.getCurrentDirElements();

+        files = files.sort(sortFiles);

+        

+        var ul = $('#' + v_mainId).find("ul");

+        ul.children().remove();

+        for (var i = 0; i < files.length; ++i) {

+            

+            var type = files[i]["type"];

+            var path = files[i]["name"];

+            var displayName = files[i]["displayName"];

+            var size = files[i]["size"];

+            var timestamp = files[i]["timestamp"];

+            var id = files[i]["id"];

+            

+            var li = document.createElement('li');

+            li.setAttribute("filetype", type);

+            li.setAttribute("path", path);

+            li.setAttribute("pathId", id);

+            

+            if (type.endsWith("d")) {

+                li.innerHTML = "<span class='FileSelector_Name'>" + displayName + "</span>";

+            } else if (type.endsWith("f")) {

+                li.innerHTML = "<span class='FileSelector_Name'>" + displayName + "</span><span class='FileSelector_Size'>" + size + "</span><span class='FileSelector_Time'>" + (new Date(timestamp * 1000)).toISOString() + "</span>";

+            } else {

+                li.innerHTML = type + ": <span class='FileSelector_Name'>" + displayName + "</span><span class='FileSelector_Size'>" + size + "</span><span class='FileSelector_Time'>" + (new Date(timestamp * 1000)).toISOString() + "</span>";

+            }

+            ul.append(li);

+            

+            $(li).click(onClick);

+            $(li).dblclick(onDoubleClick);

+        }

+        

+        $("#" + v_mainId + " .FileSelector_Back").prop("disabled", !v_viewmodel.allowBack());

+        $("#" + v_mainId + " .FileSelector_Forward").prop("disabled", !v_viewmodel.allowForward());

+        

+        selectionRefresh();

+    }

+    

+    function selectionRefresh() {

+        var selection = v_viewmodel.getSelection();

+        

+        $('#' + v_mainId).find("li").each(function() {

+            var isSelected = false;

+            for (var i = 0; i < selection.length; ++i) {

+                if ($(this).attr("path") == selection[i].value) {

+                    isSelected = true;

+                    break;

+                }

+            }

+            if (isSelected) {

+                $(this).addClass("FileSelector_Selected");

+            } else {

+                $(this).removeClass("FileSelector_Selected");

+            }

+        });

+        

+        var selectionString = "";

+        for (var i = 0; i < selection.length; ++i) {

+            selectionString += selection[i].text + "; ";

+        }

+        $("#" + v_mainId + " .FileSelector_Selection").val(selectionString);

+    }

+    

+    function onClick(event) {

+        event.preventDefault();

+        event.stopPropagation();

+        

+        var obj = $(event.target).closest("li");

+        var path = obj.attr("path");

+        var id = obj.attr("pathid");

+                

+        if (event.ctrlKey) {

+            v_viewmodel.action(id, path, "ctrlclick", refresh);

+        } else {

+            v_viewmodel.action(id, path, "click", refresh);

+        }

+    }

+    

+    function onDoubleClick(event) {

+        event.preventDefault();

+        event.stopPropagation();

+        

+        var obj = $(event.target).closest("li");

+        var path = obj.attr("path");

+        var id = obj.attr("pathid");

+                

+        v_viewmodel.action(id, path, "doubleclick", refresh);

+    }

+    

+    function sortFiles(a, b) {

+        var isDirA = (a.type.endsWith("d")), isDirB = (b.type.endsWith("d"));

+        // Directories first.

+        if (isDirA && !isDirB) {

+            return -1;

+        } else if (isDirB && !isDirA) {

+            return 1;

+        } else {

+            return a.displayName.localeCompare(b.displayName);

+        }

+    }

+    

+    function setupCallbacks() {

+        $("#" + v_mainId + " .FileSelector_CreateDir").click(function() {

+            var name = prompt("Please enter the name of the new directory", "New directory");

+            if (name != undefined) {

+                v_viewmodel.createDirectory(name, refresh);

+            }

+        });

+        

+        $("#" + v_mainId + " .FileSelector_Back").click(function() {

+            v_viewmodel.back(refresh);

+        });

+        

+        $("#" + v_mainId + " .FileSelector_Forward").click(function() {

+            v_viewmodel.forward(refresh);

+        });

+        

+        $("#" + v_mainId + " .FileSelector_Home").click(function() {

+            v_viewmodel.home(refresh);

+        });

+        

+        $("#" + v_mainId + " .FileSelector_Selection").click(function() {

+            $(this).val("");

+        });

+        

+        $("#" + v_mainId + " .FileSelector_Selection").keyup(function() {

+            v_viewmodel.setSelectionManually($(this).val());

+        });

+        

+        $("#" + v_mainId + " .FileSelector_OkButton").click(function() {

+            v_viewmodel.filesSelected();

+        });

+        

+        $("#" + v_mainId + " .FileSelector_CancelButton").click(function() {

+            v_viewmodel.fileSelectionCanceled();

+        });

+    }
+}

+

+CView_FileSelector.getHelp = function() {

+    return "A file selector view.";

+};

+

+CView_FileSelector.expectsInterface = function() {

+    return [

+        {

+            "mandatory": ["filesSelected", "fileSelectionCanceled", "getCurrentDirElements", "getCurrentDir", "action",

+                "back", "forward", "allowBack", "allowForward", "home",

+                "createDirectory", "getSelection", "setSelectionManually", "getFileTypeList", "setFilter", "exists"]

+        }

+    ];

+};

+

+CView_FileSelector.getCustomDataSchema = function() {

+    var schema = {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "title": "Custom data for CView_FileSelector",

+        "type": "object",

+        "properties": {},

+        "additionalProperties": false

+    };

+    $.extend(true, schema, ViewUtils.commonViewSchema);

+    return schema;

+};

+

+//# sourceURL=WebApplicationFramework\Views\View_FileSelector.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_InputButton.js b/htdocs/WebApplicationFramework/Views/View_InputButton.js
new file mode 100644
index 0000000..8fcf3a3
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_InputButton.js
@@ -0,0 +1,51 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_InputButton(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+
+    /** constructor */
+
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_InputButton)[0];
+    var v_data = p_data;
+    if (v_data.prompt == undefined) {
+        v_data.prompt = "";
+    }
+    var base = new CView_BasicButton(p_viewmodels, p_mainId, p_parentId, p_data);
+
+    this.applicationCreated = base.applicationCreated;
+    this.refresh = base.refresh;
+
+    base.onClick = function() {
+        var inputValue = prompt(v_data.prompt);
+        if (inputValue != undefined) {
+            v_viewmodel.setValue(0, inputValue);
+        }
+    }
+}
+
+CView_InputButton.getHelp = function() {
+    return "A button view that can be used to input data.";
+};
+
+CView_InputButton.expectsInterface = function() {
+    return CView_BasicButton.expectsInterface();
+};
+
+CView_InputButton.getCustomDataSchema = function() {
+    var baseSchema = CView_BasicButton.getCustomDataSchema();
+    var schema = {
+        "properties": {
+            "prompt": {
+                "description": "The promt text.",
+                "type": "string"
+            }
+        }
+    };
+    $.extend(true, baseSchema, schema);
+    return baseSchema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_ButtonForDownload.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_JSONEditor.css b/htdocs/WebApplicationFramework/Views/View_JSONEditor.css
new file mode 100644
index 0000000..47d1ca5
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_JSONEditor.css
@@ -0,0 +1,81 @@
+DIV.JSONEditor DIV.row {
+    border: 1px solid #DDDDDD;
+    padding: 2px;
+    margin: 2px;
+}
+
+DIV.JSONEditor {
+    width: 100%;
+    height: 100%;
+    border: 2px solid #aaa;
+    background-color: #EEEEEE;
+    box-sizing: border-box;
+}
+
+DIV.JSONEditor > DIV:last-child {
+    overflow: auto;
+    height: calc(100% - 20px);
+}
+
+.JSONEditor_Header {
+    background-color: #888888;
+    overflow: hidden;
+    white-space: nowrap;
+    display: block;
+    height: 20px;
+    width: 100%;
+    position: relative;
+    text-align: center;
+}
+
+.JSONEditor_Header > h3 {
+    margin: auto auto;
+    height: 20px;
+    font-weight: bold;
+    text-align: center;
+    padding: 0px;
+}
+
+.JSONEditor_Header > button {
+    display: block;
+    position: absolute;
+    top: 0;
+    background-color: #d66;
+    border: 2px solid #d66;
+    font-weight: bold;
+    height: 20px;
+    color: white;
+    padding: 0px;
+}
+
+.JSONEditor_Header > .JSONEditor_Save {
+    width: 50px;
+    left: 0;
+}
+
+.JSONEditor_Header > .JSONEditor_Close {
+    width: 20px;
+    right: 0;
+}
+
+.JSONEditor_Header > button:hover {
+    background-color: red;
+}
+
+DIV.JSONEditor .tabs > .ui-state-active {
+    background-color: #4CAF50;
+    color: white;
+}
+
+DIV.JSONEditor .tabs > .ui-widget-header {
+    background-color: #c5c5c5;
+}
+
+DIV.JSONEditor .tabs > .ui-widget-header:hover {
+    background-color: #999;
+    color: white;
+}
+
+DIV.JSONEditor .tabs {
+    height: auto;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_JSONEditor.js b/htdocs/WebApplicationFramework/Views/View_JSONEditor.js
new file mode 100644
index 0000000..8311b7e
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_JSONEditor.js
@@ -0,0 +1,201 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_JSONEditor(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_JSONEditor)[0];
+    var v_viewId = p_mainId;
+    var v_parentId = p_parentId;
+
+    var v_editorId = v_viewId + "_Editor";
+    var v_editor;
+    var v_editorDiv;
+
+    var v_customData = p_data;
+    if (v_customData["class"] == undefined) {
+        v_customData["class"] = "JSONEditor";
+    }
+
+    var v_name = "";
+    if (v_customData.headerText != undefined) {
+        v_name = v_customData.headerText;
+    }
+
+    var v_this = this;
+
+    /** public functions */
+
+    this.applicationCreated = function() {
+        JSONEditor.defaults.options.theme = 'jqueryui';
+        JSONEditor.defaults.editors.integer = JSONEditor.defaults.editors.number.extend({
+            sanitize: function(value) {
+                return value + "";
+            }
+        });
+
+        $("#" + v_viewId).remove();
+        $("#" + v_parentId).append('<div id="' + v_viewId + '" class="' + v_customData["class"] + '"></div>');
+        v_editorDiv = $("#" + v_viewId);
+
+        v_editorDiv.append('<div id="' + v_viewId + '_Header" class="' + v_customData["class"] + '_Header"><h3>' + v_name + '</h3></div>');
+
+        $("#" + v_viewId + "_Header").append('<button id="' + v_viewId + '_Save" class="JSONEditor_Save">Save</button>');
+        if (!v_customData.manualSaveRequired) {
+            $('#' + v_viewId + '_Save').hide();
+        } else {
+            $('#' + v_viewId + '_Save').on("click", submit);
+        }
+
+        if (v_customData.closeable) {
+            $("#" + v_viewId + "_Header").append('<button id="' + v_viewId + '_Close" class="JSONEditor_Close">X</button>');
+            $("#" + v_viewId + "_Close").on("click", close);
+        }
+        v_editorDiv.append('<div id="' + v_viewId + '_Editor"></div>');
+
+        v_editorDiv.on("keydown", function(event) {
+            event.stopPropagation();
+        });
+
+        v_editorDiv.on('input propertychange', 'input', function() {
+            this.dispatchEvent(createEvent('change'));
+        });
+
+        if (v_customData.editorOptions == undefined) {
+            v_customData.editorOptions = {
+                "disable_edit_json": true,
+                "keep_oneof_values": false,
+                "display_required_only": true
+            }
+        }
+
+        v_customData.editorOptions.schema = v_viewmodel.getSchema();
+        v_editor = new JSONEditor(document.getElementById(v_viewId + "_Editor"), v_customData.editorOptions);
+
+        if (!v_customData.manualSaveRequired) {
+            v_editor.on("change", submit);
+        }
+
+        if (v_customData.draggable) {
+            var handle = $("#" + v_viewId + "_Header > H3");
+            handle.css("cursor", "move");
+            v_editorDiv.css("position", "absolute");
+            v_editorDiv.draggable({
+                containment: [$("#" + v_parentId).offset().left, $("#" + v_parentId).offset().top, 20000, 20000],
+                scroll: true,
+                handle: handle
+            });
+        }
+
+        if (v_customData.draggable && v_customData.offset != undefined) {
+            v_editorDiv.offset(v_customData.offset);
+            // in IE and chrome we need to set the offset twice so it gets calculated correctly
+            v_editorDiv.offset(v_customData.offset);
+        }
+    };
+
+    this.refresh = function(p_fullRefresh) {
+        function dataArrived(data) {
+            v_editor.setValue(data);
+        }
+
+        if (p_fullRefresh) {
+            if (v_customData.initOnRefresh) {
+                v_this.applicationCreated();
+            }
+            v_viewmodel.getJSONData(dataArrived);
+        }
+    };
+
+    /** private functions */
+
+    function submit() {
+        var errors = v_editor.validate(v_editor.getValue());
+        if (errors.length === 0) {
+            v_viewmodel.setJSONData(v_editor.getValue());
+        }
+    }
+
+    function close() {
+        v_editorDiv.remove();
+    }
+}
+
+CView_JSONEditor.getHelp = function() {
+    return "A JSON schema editor view.";
+};
+
+CView_JSONEditor.expectsInterface = function() {
+    return [
+        {
+            "mandatory": ["getSchema", "setJSONData", "getJSONData"]
+        }
+    ];
+};
+
+CView_JSONEditor.getCustomDataSchema = function() {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CView_JSONEditor",
+        "type": "object",
+        "properties": {
+            "class": {
+                "description": "The css class of the JSON Editor",
+                "type": "string",
+                "default": "JSONEditor"
+            },
+            "headerText": {
+                "description": "The title of the editor.",
+                "type": "string"
+            },
+            "manualSaveRequired": {
+                "description": "Whether we must press the save button to save the data.",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            },
+            "initOnRefresh": {
+                "description": "Whether we initialize the editor on every full refresh. Useful if the same editor is used with different schemas.",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            },
+            "closeable": {
+                "description": "Whether we want to allow closing the editor.",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            },
+            "draggable": {
+                "description": "Whether we want the editor to be draggable.",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            },
+            "offset": {
+                "description": "The offset of the editor. Only works with draggable.",
+                "type": "object",
+                "properties": {
+                    "top": {
+                        "type": "integer"
+                    },
+                    "left": {
+                        "type": "integer"
+                    }
+                }
+            },
+            "editorOptions": {
+                "type": "object",
+                "description": 'The JSON Editor options, see https://github.com/jdorn/json-editor for more details.',
+                "additionalProperties": true
+            }
+        },
+        "additionalProperties": false
+    };
+    $.extend(true, schema, ViewUtils.commonViewSchema);
+    return schema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_JSONEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Label.css b/htdocs/WebApplicationFramework/Views/View_Label.css
new file mode 100644
index 0000000..45a5ce6
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Label.css
@@ -0,0 +1,45 @@
+.BasicLabel,
+.HeaderLabel,
+.StripedLabel {
+    width: 100%;
+    height: 100%;
+    box-sizing: border-box;
+    padding-right: 5px;
+}
+
+.StripedLabel {
+    background: repeating-linear-gradient(144deg, #F1F1F1, #F1F1F1 5px, #E8E8E8 5px, #E8E8E8 10px);
+    background: -moz-repeating-linear-gradient(144deg, #F1F1F1, #F1F1F1 5px, #E8E8E8 5px, #E8E8E8 10px);
+}
+
+.HeaderLabel {
+    background-color: #bbbbbb;
+    /*font-size: 12px;*/
+}
+
+.BasicLabel > DIV,
+.StripedLabel > DIV {
+    width: 0px;
+    height: 25px;
+    display: inline-block;
+    vertical-align: middle;
+}
+
+.BasicLabel input,
+.StripedLabel input {
+    border: 0px;
+    outline: none;
+    -webkit-box-shadow: none;
+    -moz-box-shadow: none;
+    box-shadow: none;
+    cursor: default;
+    width: 100%;
+    vertical-align: middle;
+    display: inline-block;
+}
+
+.BasicLabel input:disabled,
+.StripedLabel input:disabled {
+    background-color: transparent;
+    color: #555;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Label.js b/htdocs/WebApplicationFramework/Views/View_Label.js
new file mode 100644
index 0000000..1993764
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Label.js
@@ -0,0 +1,153 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_Label(p_viewmodels, p_mainId, p_parentId, p_data) {

+    "use strict";

+    

+    /** constructor */

+    

+    var v_viewmodels = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_Label);

+    var v_viewmodel = v_viewmodels[0];

+    var v_conditionViewmodel = v_viewmodels[1];

+    var v_writableViewmodel = v_viewmodels[2];

+    

+    var v_mainId = p_mainId;

+    var v_parentId = p_parentId;

+    var v_customData = p_data;

+    

+    var v_label;

+    var v_selected = false;

+    var v_currentValue = "";

+    

+    var v_this = this;

+    

+    /** public functions */

+

+    this.applicationCreated = function() {

+        $("#" + v_parentId).append(getHtml());

+        if (v_customData.isElementLabelPresent) {

+            v_label = ViewUtils.addLabel(v_mainId, v_customData.elementText);

+        }

+        if (v_customData.class != undefined) {

+            $("#" + v_mainId).addClass(v_customData.class);

+        } else {

+            $("#" + v_mainId).addClass("BasicLabel");

+        }

+        

+        var input = $("#" + v_mainId + " input");

+        

+        if (v_customData.disabled !== true && v_customData.text == undefined && v_viewmodel != undefined) {

+            input.on({

+                focus: function() {

+                    v_selected = true;

+                },

+                blur: function() {

+                    var newValue = $(this).val();

+                    if (newValue != v_currentValue) {

+                        v_viewmodel.setValue(0, newValue);

+                    }

+                    v_selected = false;

+                },

+                keydown: function(event) {

+                    if (event.keyCode == 13) {

+                        $(this).blur();

+                    }

+                }

+            });

+        }

+        

+        if (v_viewmodel == undefined || v_customData.text != undefined) {

+            $("#" + v_mainId + " > input").prop('disabled', true);

+        }

+        

+        ViewUtils.addTooltip(v_mainId, v_customData);

+    };

+

+    this.refresh = function(p_fullRefresh) {

+        if (ViewUtils.checkVisibility(v_conditionViewmodel, v_mainId) && v_viewmodel != undefined) {

+            var dataObject = v_viewmodel.getListWithElementInfo();

+            if (v_customData.text != undefined || dataObject == undefined || dataObject.values[0] == undefined) {

+                return;

+            }

+            

+            var input = $("#" + v_mainId + " input");

+            

+            if (p_fullRefresh && v_customData.isElementLabelPresent && v_customData.elementText == undefined) {

+                v_label.text(dataObject.values[0].element);

+            }

+            

+            if (!v_selected && v_customData.text == undefined) {

+                var text = "";

+                if(dataObject.values[0].val != undefined) {

+                    $("#" + v_mainId + " > *").css("display", "");

+                    $("#" + v_mainId).removeClass("NoData");

+                    text = dataObject.values[0].val;

+                } else {

+                    $("#" + v_mainId + " > *").css("display", "none");

+                    $("#" + v_mainId).addClass("NoData");

+                }

+                // we need both...

+                input.val(text);

+                input[0].setAttribute('value', text);

+                v_currentValue = text;

+            }

+            

+            if (v_customData.disabled !== true && dataObject.values[0] != undefined && dataObject.values[0].isWritable && (v_writableViewmodel == undefined || v_writableViewmodel.isWritable())) {

+                $("#" + v_mainId + " > input").prop('disabled', false);

+            } else {

+                $("#" + v_mainId + " > input").prop('disabled', true);

+            }

+        }

+    };

+

+    /** private functions */

+    

+    function getHtml() {

+        return '<div id="' + v_mainId + '">' +

+            '<div></div><input value="' + (v_customData.text != undefined ? v_customData.text : '') + '">' + 

+        '</div>';

+    }

+}

+

+CView_Label.getHelp = function() {

+    return "A single label that can also be used for input.";

+}

+

+CView_Label.expectsInterface = function() {

+    return [

+        {

+            "optional": ["setValue", "getListWithElementInfo"]

+        },

+        {

+            "optional": ["getState"]

+        },

+        {

+            "optional": ["isWritable"]

+        }

+    ];

+};

+

+CView_Label.getCustomDataSchema = function() {

+    var schema = {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "title": "Custom data for CView_Label",

+        "type": "object",

+        "properties": {

+            "class": {

+                "type": "string",

+                "description": "the css class of the view",

+                "default": "BasicLabel"

+            },

+            "text": {

+                "type": "string",

+                "description": "the label text"

+            }

+        },

+        "additionalProperties": false

+    };

+    $.extend(true, schema, ViewUtils.commonViewSchema, ViewUtils.commonElementSchema);

+    return schema;

+};

+//# sourceURL=WebApplicationFramework\Views\View_Label.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_MultipliedViewAligner.js b/htdocs/WebApplicationFramework/Views/View_MultipliedViewAligner.js
new file mode 100644
index 0000000..6f85c2c
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_MultipliedViewAligner.js
@@ -0,0 +1,182 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_MultipliedViewAligner(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+    
+    /** constructor */
+    
+    var v_mainId = p_mainId;
+    var v_parentId = p_parentId;
+    var v_customData = p_data;
+    
+    var v_viewmodels = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_MultipliedViewAligner);
+    var v_dataViewmodel = v_viewmodels[0];
+    var v_flexViewmodel = v_viewmodels[1];
+    var v_conditionViewmodel = v_viewmodels[2];
+    
+    var v_multipliedSubviews = [];
+    var v_alignerSize = 0;
+    
+    var v_this = this;
+    
+    /** public functions */
+
+    this.applicationCreated = function() {
+        preprocessSubviewDescriptors(v_customData, 0);
+    };
+
+    this.refresh = function(p_fullRefresh) {
+        if (p_fullRefresh) {
+            $("#" + v_parentId).empty();
+            v_multipliedSubviews = [];
+            fullRefresh();
+        } else if (ViewUtils.checkVisibility(v_conditionViewmodel, v_mainId)) {
+            for (var i = 0; i < v_multipliedSubviews.length; ++i) {
+                v_multipliedSubviews[i].refresh();
+            }
+        }
+    };
+    
+    /** private functions */
+    
+    function preprocessSubviewDescriptors(descriptor, counter) {
+        if (descriptor.multipliedSubviews != undefined) {
+            descriptor.idsCreating = [];
+            for (var i = 0; i < descriptor.multipliedSubviews.length; ++i) {
+                descriptor.idsCreating[i] = "" + counter;
+                counter = preprocessSubviewDescriptors(descriptor.multipliedSubviews[i], counter + 1);
+            }
+        }
+        
+        return counter;
+    }
+    
+    function fullRefresh() {
+        var viewmodelBundle = v_dataViewmodel.getViewmodelBundle();
+        v_alignerSize = viewmodelBundle.length;
+        v_customData.idsCreating = [];
+        for (var i = 0; i < viewmodelBundle.length; ++i) {
+            v_customData.idsCreating.push(v_mainId + "_" + i);
+        }
+        createAligner();
+        for (var i = 0; i < viewmodelBundle.length; ++i) {
+            createSubviews(viewmodelBundle[i], v_customData.multipliedSubviews, [v_customData.idsCreating[i]], v_mainId + "_" + i + "_");
+        }
+    }
+    
+    function createAligner() {
+        var aligner = new CView_Aligner(p_viewmodels, v_mainId, v_parentId, v_customData);
+        if (v_customData.flexCalculation || v_customData.resizable) {
+            aligner.getLenghtsFromViewmodel = getLenghtsFromViewmodel;
+        }
+        aligner.applicationCreated();
+        ViewUtils.applyCss(v_customData, v_mainId);
+        ViewUtils.processCss(v_customData, v_parentId);
+    }
+    
+    function getLenghtsFromViewmodel() {
+        var sizes = [];
+        for (var i = 0; i < v_alignerSize; ++i) {
+            sizes[i] = ((1 / v_alignerSize) * 100) + "%";
+        }
+        return sizes;
+    }
+    
+    function createSubviews(viewmodelBundle, subviewDescriptors, parentIds, idPrefix) {
+        if (subviewDescriptors != undefined) {
+            for (var i = 0; i < subviewDescriptors.length; ++i) {
+                var viewmodels = getViewmodels(viewmodelBundle, subviewDescriptors[i].viewmodelIdexes);
+                var parentId = parentIds[i];
+                var id = parentId + "_subview";
+                var customData = mcopy(subviewDescriptors[i]);
+                if (customData.idsCreating != undefined) {
+                    for (var j = 0; j < customData.idsCreating.length; ++j) {
+                        customData.idsCreating[j] = idPrefix + customData.idsCreating[j];
+                    }
+                }
+                
+                if (subviewDescriptors[i].subView != undefined && window[subviewDescriptors[i].subView] != undefined) {
+                    var subview = new window[subviewDescriptors[i].subView](viewmodels, id, parentId, customData);
+                    subview.applicationCreated();
+                    ViewUtils.applyCss(customData, id);
+                    ViewUtils.processCss(customData, parentId);
+                    v_multipliedSubviews.push(subview);
+                    subview.refresh(true);
+                    
+                    if (subviewDescriptors[i].subView != "CView_MultipliedViewAligner") {
+                        createSubviews(viewmodelBundle, customData.multipliedSubviews, customData.idsCreating, idPrefix);
+                    }
+                } else {
+                    alert("Could not create subview " + subviewDescriptors[i].subView);
+                }
+            }
+        }
+    }
+    
+    function getViewmodels(bundle, indexes) {
+        var viewmodels = [];
+        if (indexes != undefined) {
+            for (var i = 0; i < indexes.length; ++i) {
+                viewmodels.push(bundle[indexes[i]]);
+            }
+        }
+        return viewmodels;
+    }
+}
+
+CView_MultipliedViewAligner.getHelp = function() {
+    return "An aligner that creates its subviews specified in the custom data using a viewmodel bundle. See CView_Aligner.";
+};
+
+CView_MultipliedViewAligner.expectsInterface = function() {
+    var expectedInterface = CView_Aligner.expectsInterface();
+    expectedInterface.unshift({
+        "optional": ["getState"]
+    });
+    expectedInterface.unshift({
+        "optional": ["getChildPercentagesFromFlex"]
+    });
+    expectedInterface.unshift({
+        "mandatory": ["getViewmodelBundle"]
+    });
+    return expectedInterface;
+};
+
+CView_MultipliedViewAligner.getCustomDataSchema = function() {
+    var schema = CView_Aligner.getCustomDataSchema();
+    schema.title = "Custom data for CView_MultipliedViewAligner";
+    schema.properties.multipliedSubviews = {
+        "type": "array",
+        "format": "tabs",
+        "description": "The subviews and their custom data.",
+        "items": {
+            "type": "object",
+            "title": "subview",
+            "properties": {
+                "subView" : {
+                    "type" : "string",
+                    "description": "The class name of the subview."
+                },
+                "viewmodelIdexes": {
+                    "type": "array",
+                    "format": "table",
+                    "description": "The index of the connected viewmodels in a bundle.",
+                    "items": {
+                        "type": "integer",
+                        "min": 0
+                    }
+                }
+            },
+            "required": ["subView"],
+            "additionalProperties": true
+        },
+        "minItems": 1
+    }
+    schema.required = ["multipliedSubviews"];
+    return schema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_MultipliedViewAligner.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Paging.js b/htdocs/WebApplicationFramework/Views/View_Paging.js
new file mode 100644
index 0000000..0ddda38
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Paging.js
@@ -0,0 +1,120 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_Paging(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+    
+    /** constructor */
+    
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_Paging)[0];
+    var v_mainId = p_mainId;
+    var v_parentId = p_parentId;
+    var v_customData = p_data;
+    
+    var v_this = this;
+    
+    /** public functions */
+
+    this.applicationCreated = function() {
+        $("#" + v_parentId).append(getHtml());
+        if (v_customData.class != undefined) {
+            $("#" + v_mainId).addClass(v_customData.class);
+        } else {
+            $("#" + v_mainId).addClass("BasicPaging");
+        }
+        setupCallbacks();
+    };
+
+    this.refresh = function(p_fullRefresh) {
+        var filter = v_viewmodel.getRangeFilter();
+        var size = v_viewmodel.getSize();
+        var offset;
+        if (filter.offset != undefined) {
+            offset = filter.offset;
+        } else {
+            offset = 0;
+        }
+        var count;
+        if (filter.count != undefined) {
+            count = filter.count;
+        } else {
+            count = size - offset;
+        }
+        var text = "" + offset + " - " + (offset + count) + " / " + size;
+        $('#' + v_mainId + ' > label').html(text);
+    };
+
+    /** private functions */
+    
+    function getHtml() {
+        var html = '<div id="' + v_mainId + '">' +
+            '<button id="' + v_mainId + '_lt3">&lt&lt&lt</button>' +
+            '<button id="' + v_mainId + '_lt2">&lt&lt</button>' +
+            '<button id="' + v_mainId + '_lt1">&lt</button>' +
+            '<label id="' + v_mainId + '_label"></label>' +
+            '<button id="' + v_mainId + '_gt1">&gt</button>' +
+            '<button id="' + v_mainId + '_gt2">&gt&gt</button>' +
+            '<button id="' + v_mainId + '_gt3">&gt&gt&gt</button>' +
+        '</div>';
+        return html;
+    }
+    
+    function setupCallbacks() {
+        $('#' + v_mainId + '_lt3').click(function() {
+            v_viewmodel.changeFilter({"offset" : {"to": 0}});
+        });
+        $('#' + v_mainId + '_lt2').click(function() {
+            var filter = v_viewmodel.getRangeFilter();
+            v_viewmodel.changeFilter({"offset" : {"by": -filter.count}});
+        });
+        $('#' + v_mainId + '_lt1').click(function() {
+            v_viewmodel.changeFilter({"offset" : {"by": -1}});
+        });
+        $('#' + v_mainId + '_gt1').click(function() {
+            v_viewmodel.changeFilter({"offset" : {"by": 1}});
+        });
+        $('#' + v_mainId + '_gt2').click(function() {
+            var filter = v_viewmodel.getRangeFilter();
+            v_viewmodel.changeFilter({"offset" : {"by": filter.count}});
+        });
+        $('#' + v_mainId + '_gt3').click(function() {
+            var size = v_viewmodel.getSize();
+            var filter = v_viewmodel.getRangeFilter();
+            v_viewmodel.changeFilter({"offset" : {"to": size - filter.count}});
+        });
+    }
+}
+
+CView_Paging.getHelp = function() {
+    return "A small paging view that can control the viewmodel's range filter.";
+}
+
+CView_Paging.expectsInterface = function() {
+    return [
+        {
+            "mandatory": ["getSize", "getRangeFilter", "changeFilter"]
+        }
+    ];
+}
+
+CView_Paging.getCustomDataSchema = function() {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CView_Paging",
+        "type": "object",
+        "properties": {
+            "class": {
+                "description": "The css class of the pager",
+                "type": "string",
+                "default": "BasicPaging"
+            }
+        },
+        "additionalProperties": false
+    };
+    $.extend(true, schema, ViewUtils.commonViewSchema);
+    return schema;
+}
+
+//# sourceURL=WebApplicationFramework\Views\View_Paging.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_ProgressBar.css b/htdocs/WebApplicationFramework/Views/View_ProgressBar.css
new file mode 100644
index 0000000..a77020a
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ProgressBar.css
@@ -0,0 +1,30 @@
+.ProgressBar {
+    width: 100%;
+    height: 100%;
+    position: relative;
+}
+
+.ProgressBar svg {
+    width: 100%;
+    height: 100%;
+}
+
+.ProgressBar label.progressText {
+    position: absolute;
+    width: 200px;
+    height: 30px;
+    top: calc(33% + 115px);
+    left: calc(50% - 100px);
+    font-size: 20px;
+    text-align: center;
+}
+
+.ProgressBar label.progressPercentage {
+    position: absolute;
+    width: 200px;
+    height: 30px;
+    top: calc(33% - 15px);
+    left: calc(50% - 100px);
+    font-size: 20px;
+    text-align: center;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_ProgressBar.js b/htdocs/WebApplicationFramework/Views/View_ProgressBar.js
new file mode 100644
index 0000000..fadd2ff
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_ProgressBar.js
@@ -0,0 +1,141 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_ProgressBar(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+    
+    /** constructor */
+    
+    var v_mainId = p_mainId;
+    var v_parentId = p_parentId;
+    var v_customData = p_data;
+    if (v_customData.stroke == undefined) {
+        v_customData.stroke = "#4CAF50";
+    }
+    if (v_customData.strokeWidth == undefined) {
+        v_customData.strokeWidth = 20;
+    }
+    if (v_customData.radius == undefined) {
+        v_customData.radius = 100;
+    }
+    
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_ProgressBar)[0];
+    var v_this = this;
+    
+    /** public functions */
+
+    this.applicationCreated = function() {
+        $("#" + v_parentId).append(getHtml());
+        if (v_customData.isElementLabelPresent) {
+            ViewUtils.addLabel(v_mainId, v_customData.elementText);
+        }
+        if (v_customData.class != undefined) {
+            $("#" + v_mainId).addClass(v_customData.class);
+        } else {
+            $("#" + v_mainId).addClass("ProgressBar");
+        }
+    };
+
+    this.refresh = function() {
+        if (v_viewmodel != undefined) {
+            var list = v_viewmodel.getList();
+            updateCircle(list.values[0][0] != "" ? list.values[0][0] : 100.0, list.values[1][0]);
+        }
+    };
+
+    /** private functions */
+    
+    function getHtml() {
+        return '<div id="' + v_mainId + '"><svg><path fill="none" stroke="' + v_customData.stroke + '" stroke-width="' + v_customData.strokeWidth + '"></path></svg><label class="progressText"></label><label class="progressPercentage"></label></div>';
+    }
+    
+    function updateCircle(percent, text) {
+        $("#" + v_mainId + " path").attr("d", getArc(percent));
+        if (text != undefined) {
+            $("#" + v_mainId + " .progressText").text(text);
+            $("#" + v_mainId + " .progressPercentage").text(percent + "%");
+        }
+    }
+    
+    function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
+        var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
+
+        return {
+            x: centerX + (radius * Math.cos(angleInRadians)),
+            y: centerY + (radius * Math.sin(angleInRadians))
+        };
+    }
+
+    function getArc(percent){
+        if (percent == 100.0) {
+            percent = 99.99;
+        }
+        
+        var radius = v_customData.radius;
+        var startAngle = 0;
+        var endAngle = 360.0 * percent / 100.0;
+        
+        var centerY = $("#" + v_mainId).height() / 3;
+        var centerX = $("#" + v_mainId).width() / 2;
+                
+        var start = polarToCartesian(centerX, centerY, radius, endAngle);
+        var end = polarToCartesian(centerX, centerY, radius, startAngle);
+
+        var arcSweep = endAngle - startAngle <= 180 ? "0" : "1";
+
+        var d = [
+            "M", start.x, start.y, 
+            "A", radius, radius, 0, arcSweep, 0, end.x, end.y
+        ].join(" ");
+                
+        return d;       
+    }
+}
+
+CView_ProgressBar.getHelp = function() {
+    return "A progreesbar view. Requires a list whose first element is a percentage and the second is an optional text.";
+}
+
+CView_ProgressBar.expectsInterface = function() {
+    return [
+        {
+            "mandatory": ["getList"]
+        }
+    ];
+};
+
+CView_ProgressBar.getCustomDataSchema = function() {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CView_ProgressBar",
+        "type": "object",
+        "properties": {
+            "class": {
+                "type": "string",
+                "description": "the css class of the progress bar"
+            },
+            "stroke": {
+                "type": "string",
+                "description": "the color of the progress circle in hex format",
+                "pattern": "^#(?:[0-9a-fA-F]{3}){1,2}$",
+                "default": "#4CAF50"
+            },
+            "strokeWidth": {
+                "type": "integer",
+                "description": "the width of the circle's ring",
+                "default": 20
+            },
+            "radius": {
+                "type": "integer",
+                "description": "the radius of the circle in pixels",
+                "default": 100
+            }
+        },
+        "additionalProperties": false
+    };
+    $.extend(true, schema, ViewUtils.commonViewSchema);
+    return schema;
+};
+//# sourceURL=WebApplicationFramework\Views\View_ProgressBar.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Scroll.css b/htdocs/WebApplicationFramework/Views/View_Scroll.css
new file mode 100644
index 0000000..6c3795f
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Scroll.css
@@ -0,0 +1,62 @@
+.View_Scroll {
+    width : 14px;
+    height: 100%;
+    background-color: #eeeeee;
+    position: absolute;
+    top: 0px;
+}
+
+.View_Scroll_Top {
+    height : 14px;
+    width: 100%;
+    position: absolute;
+    z-index: 2;
+    background-color: #e0e0e0;
+    background-image: url("WebApplicationFramework/Res/arrowUp.png");
+    background-position: center center;
+    background-repeat: no-repeat;
+}
+
+.View_Scroll_Top:hover {
+    background-color: #e6e6e6;
+}
+
+.View_Scroll_Bar {
+    width: 100%;
+    height: 100%;
+    position: relative;
+}
+
+.View_Scroll_Handle {
+    width: 100%;
+    position: absolute;
+    z-index: 1;
+    background-color: #e0e0e0;
+    background-image: url("WebApplicationFramework/Res/grip.png");
+    background-position: center center;
+    background-repeat: no-repeat;
+    border: 1px solid #d6d6d6;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+}
+
+.View_Scroll_Handle:hover {
+    background-color: #e6e6e6;
+}
+
+.View_Scroll_Bottom {
+    height: 14px;
+    width: 100%;
+    position: absolute;
+    bottom: 0px;
+    z-index: 2;
+    background-color: #e0e0e0;
+    background-image: url("WebApplicationFramework/Res/arrowDown.png");
+    background-position: center center;
+    background-repeat: no-repeat;
+}
+
+.View_Scroll_Bottom:hover {
+    background-color: #e6e6e6;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Scroll.js b/htdocs/WebApplicationFramework/Views/View_Scroll.js
new file mode 100644
index 0000000..d58ded7
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Scroll.js
@@ -0,0 +1,226 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_Scroll(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+    
+    /** constructor */
+    
+    var v_viewmodels = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_Scroll);
+    var v_viewmodel = v_viewmodels[0];
+    var v_viewPortSizeViewmodel = v_viewmodels[1];
+    
+    var v_mainId = p_mainId;
+    var v_parentId = p_parentId;
+    var v_customData = p_data;
+    
+    if (v_customData.clickOnScrollBarBehaviour == undefined) {
+        v_customData.clickOnScrollBarBehaviour = "bigstep";
+    }
+    
+    if (v_customData.bigStep == undefined) {
+        v_customData.bigStep = 10;
+    }
+    
+    var v_refreshEnabled = true;
+    
+    var v_numberOfValues;
+    var v_currentValue;
+    var v_viewportSize = 1;
+    
+    var v_height;
+    var v_handleOffset;
+    var v_handleHeight;
+    
+    var BUTTON_HEIGHT = 14;
+    
+    var v_this = this;
+    
+    /** public functions */
+
+    this.applicationCreated = function() {
+        $("#" + v_parentId).append(getHtml());
+        $("#" + v_mainId).css("right", - $("#" + v_parentId)[0].scrollLeft);
+        setupCallbacks();
+    };
+
+    this.refresh = function(p_fullRefresh) {
+        if (v_refreshEnabled) {
+            var range = v_viewmodel.getRange();
+            v_numberOfValues = range.max - range.min;
+            v_currentValue = v_viewmodel.getPosition();
+            
+            if (v_viewPortSizeViewmodel.getViewportSize != undefined) {
+                v_viewportSize = v_viewPortSizeViewmodel.getViewportSize();
+            }
+            
+            //$("#" + v_mainId).css("right", $("#" + v_parentId).width() - $("#" + v_parentId)[0].scrollWidth);
+
+            v_height = $('#' + v_mainId + '_bar').height() - 2 * BUTTON_HEIGHT;
+            setHandleHeight();
+            v_height = $('#' + v_mainId + '_bar').height() - 2 * BUTTON_HEIGHT - v_handleHeight;
+            setOffset();
+        }
+    };
+
+    /** private functions */
+    
+    function getHtml() {
+        var html = '<div id="' + v_mainId + '" class="View_Scroll">' +
+            '<div id="' + v_mainId + '_top" class="View_Scroll_Top"></div>' +
+            '<div id="' + v_mainId + '_bar" class="View_Scroll_Bar">' +
+                '<div id="' + v_mainId + '_handle" class="View_Scroll_Handle"></div>' +
+            '</div>' +
+            '<div id="' + v_mainId + '_bottom" class="View_Scroll_Bottom"></div>' +
+        '</div>';
+        return html;
+    }
+    
+    function setOffset() {
+        var proportion = v_currentValue / (v_numberOfValues - 1);
+        v_handleOffset = Math.ceil((v_height * proportion) + BUTTON_HEIGHT); // +BUTTON_HEIGHT for the top "button"
+        if (v_handleOffset > v_height + BUTTON_HEIGHT) {
+            v_handleOffset = v_height + BUTTON_HEIGHT;
+        }
+        $('#' + v_mainId + '_handle').css("top", v_handleOffset);
+    }
+    
+    function setHandleHeight() {
+        v_handleHeight = Math.ceil((v_viewportSize * v_height) / (v_viewportSize + v_numberOfValues));
+        if (v_handleHeight < BUTTON_HEIGHT) {
+            v_handleHeight = BUTTON_HEIGHT; // the min handle height
+        }
+        $('#' + v_mainId + '_handle').css("height", v_handleHeight);
+    }
+    
+    function onScroll(event) {
+        var up = false;
+        var down = false;
+        if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) {
+            v_currentValue = v_viewmodel.getPosition();
+            v_viewmodel.setPosition(v_currentValue - 1);
+            up = true;
+        } else {
+            v_currentValue = v_viewmodel.getPosition();
+            v_viewmodel.setPosition(v_currentValue + 1);
+            down = true;
+        }
+        
+        if ((v_currentValue != 0 || down) && (v_currentValue != v_numberOfValues - 1 || up)) {
+            event.stopPropagation();
+            event.preventDefault();
+        }
+    }
+    
+    function onHorizontalScroll() {
+        $("#" + v_mainId).css("right", - $("#" + v_parentId)[0].scrollLeft);
+    }
+    
+    function setupCallbacks() {
+        $('#' + v_mainId + '_top').click(function(event) {
+            v_currentValue = v_viewmodel.getPosition();
+            v_viewmodel.setPosition(v_currentValue - 1);
+            event.stopPropagation();
+        });
+        
+        $('#' + v_mainId + '_bottom').click(function(event) {
+            v_currentValue = v_viewmodel.getPosition();
+            v_viewmodel.setPosition(v_currentValue + 1);
+            event.stopPropagation();
+        });
+        
+        $('#' + v_mainId + '_bar').click(function(e) {
+            var barTop = $(this).offset().top;
+            var clickTop = e.pageY;
+            if (v_customData.clickOnScrollBarBehaviour == "bigstep") {
+                v_currentValue = v_viewmodel.getPosition();
+                if (clickTop - barTop - BUTTON_HEIGHT > v_handleOffset) {
+                    v_viewmodel.setPosition(v_currentValue + v_customData.bigStep);
+                } else {
+                    v_viewmodel.setPosition(v_currentValue - v_customData.bigStep);
+                }
+            } else {
+                var proportion = (clickTop - barTop - BUTTON_HEIGHT) / v_height;
+                v_viewmodel.setPosition(Math.floor((v_numberOfValues - 1) * proportion));
+            }
+        });
+        
+        $('#' + v_mainId + '_handle').click(function(e) {
+            if (v_customData.clickOnScrollBarBehaviour == "bigstep") {
+                e.stopPropagation();
+            }
+        });
+        
+        $('#' + v_parentId).on('mousewheel', onScroll);
+        $('#' + v_parentId).on('scroll', onHorizontalScroll);
+        
+        $('#' + v_mainId + '_handle').draggable({
+            "start": function() {
+                v_refreshEnabled = false;
+            },
+            "stop": function() {
+                v_refreshEnabled = true;
+            },
+            "drag": function(event, ui) {
+                if (ui.position.top < BUTTON_HEIGHT) {
+                    ui.position.top = BUTTON_HEIGHT;
+                } else if (ui.position.top > v_height + BUTTON_HEIGHT) {
+                    ui.position.top = v_height + BUTTON_HEIGHT;
+                }
+                
+                var proportion = (ui.position.top - BUTTON_HEIGHT) / v_height;
+                v_viewmodel.setPosition(Math.floor((v_numberOfValues - 1) * proportion));
+            },
+            "axis": "y",
+            "scroll": false
+        });
+        
+        $('#' + v_mainId).on("remove", function () {
+            $('#' + v_parentId).off('mousewheel', onScroll);
+            $('#' + v_parentId).off('scroll', onHorizontalScroll);
+        });
+    }
+}
+
+CView_Scroll.getHelp = function() {
+    return "A scroll view that can be used to scroll data. It will appear on the right side of its parent.";
+}
+
+CView_Scroll.expectsInterface = function() {
+    return [
+        {
+            "mandatory": ["getRange", "getPosition", "setPosition"]
+        },
+        {
+            "optional": ["getViewportSize"]
+        }
+    ];
+}
+
+CView_Scroll.getCustomDataSchema = function() {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CView_Scroll",
+        "type": "object",
+        "properties": {
+            "clickOnScrollBarBehaviour": {
+                "description": "The behaviour of the scrollbar when clicking on it (default bigstep).",
+                "type": "string",
+                "enum": ["bigstep", "jumpto"],
+                "default": "jumpto"
+            },
+            "bigStep": {
+                "description": "How many lines does the bigstep scroll. If the value is negative, de scroll will be reversed (only when clicking on the scrollbar).",
+                "type": "integer",
+                "default": 10
+            }
+        },
+        "additionalProperties": false
+    };
+    $.extend(true, schema, ViewUtils.commonViewSchema);
+    return schema;
+}
+
+//# sourceURL=WebApplicationFramework\Views\View_Scroll.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_SetupTabs.js b/htdocs/WebApplicationFramework/Views/View_SetupTabs.js
new file mode 100644
index 0000000..8f2417e
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_SetupTabs.js
@@ -0,0 +1,72 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_SetupTabs(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+    
+    /** constructor */
+    
+    var m_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_SetupTabs)[0];
+    var m_parentId = p_parentId;
+    
+    /** public functions */
+
+    this.applicationCreated = function() {};
+
+    this.refresh = function(p_fullRefresh) {
+        if (p_fullRefresh) {
+            $("#" + m_parentId).empty();
+            createTabs();
+        }
+    };
+    
+    /** private functions */
+    
+    function createTabs() {
+        function createTabRow(tabsVM, nesting, index, parentID) {
+            var setupList = tabsVM.getList().values;
+            var tabList = [];
+            var tabidList = [];
+            for (var i = 0; i < setupList[0].length; ++i) {
+                tabList[i] = setupList[0][i][0];
+                tabidList[i] = parentID + nesting + "_" + i;
+            }
+            var setupTabs = new CView_Tabs([tabsVM], "setupTabID_" + parentID, parentID, {idsCreating : tabidList, namesCreating : tabList, css: {height:"100px"}});
+            setupTabs.applicationCreated();
+            setupTabs.refresh(true);
+            var subVMs = tabsVM.getSubViewModels();
+            for (var i = 0; i < subVMs.length; ++i)
+                if (subVMs[i])
+                    createTabRow(subVMs[i], nesting + 1, i, tabidList[i]);
+        }
+
+        var tabsVM = m_viewmodel.getRecursiveSetups();
+        createTabRow(tabsVM, 0, 0, m_parentId);
+    }
+}
+
+CView_SetupTabs.getHelp = function() {
+    return "A view that displays the setup hierarchy and can be used to switch setups.";
+};
+
+CView_SetupTabs.expectsInterface = function() {
+    return [{
+        "mandatory": ["getRecursiveSetups"]
+    }];
+}
+
+CView_SetupTabs.getCustomDataSchema = function() {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CView_SetupTabs",
+        "type": "object",
+        "properties": {},
+        "additionalProperties": false
+    };
+    //$.extend(true, schema, ViewUtils.commonViewSchema);
+    return schema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_SetupTabs.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_StatusLED.css b/htdocs/WebApplicationFramework/Views/View_StatusLED.css
new file mode 100644
index 0000000..f85f2fe
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_StatusLED.css
@@ -0,0 +1,22 @@
+.StatusLED {
+    font-family:"Arial";
+    /*font-size:11px;*/
+    vertical-align: middle;
+    box-sizing: border-box;
+}
+
+.StatusLED SPAN {
+	display: inline-block; /* If you remove this, the SPAN that encloses the IMG will not be the same height. Which is most likely a problem. */
+}
+
+.StatusLED IMG {
+    height: 25px;
+    width: 25px;
+    vertical-align: middle; /* If you remove this, the IMG will be centered and the text will valign to baseline. */
+    margin-right: 5px; /* Distance between image and text */
+}
+
+.StatusLED > SPAN > LABEL {
+    vertical-align: middle;
+    margin-right: 5px;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_StatusLED.js b/htdocs/WebApplicationFramework/Views/View_StatusLED.js
new file mode 100644
index 0000000..2cd4a55
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_StatusLED.js
@@ -0,0 +1,163 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_StatusLED(p_viewmodels, p_mainId, p_parentId, p_data) {

+    "use strict";

+    /** constructor */

+    

+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_StatusLED)[0];

+    var v_conditionViewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_StatusLED)[1];

+    var v_mainId = p_mainId;

+    var v_parentId = p_parentId;

+    var v_customData = p_data;

+    

+    var v_label;

+    var v_led = "";

+    

+    var v_this = this;

+        

+    this.applicationCreated = function() {

+        $("#" + v_parentId).append(getHtml());

+        if (v_customData.isElementLabelPresent) {

+            v_label = ViewUtils.addLabel(v_mainId, v_customData.elementText);

+        }

+        $("#" + v_mainId).addClass("StatusLED");

+    };

+        

+    this.refresh = function(p_fullRefresh) {

+        if (v_viewmodel != undefined && ViewUtils.checkVisibility(v_conditionViewmodel, v_mainId)) {

+            var dataObject = v_viewmodel.getListWithElementInfo();

+            if (dataObject == undefined || dataObject.values[0] == undefined) {

+                return;

+            }

+            

+            if (p_fullRefresh && v_customData.isElementLabelPresent && v_customData.elementText == undefined) {

+                v_label.text(dataObject.values[0].element);

+            }

+            

+            var text = "";

+            var str = dataObject.values[0].val;

+            

+            if (str == undefined) {

+                $("#" + v_mainId + " > span").css("display", "none");

+                $("#" + v_mainId).addClass("NoData");

+            } else {

+                $("#" + v_mainId + " > span").css("display", "");

+                $("#" + v_mainId).removeClass("NoData");

+            }

+            

+            if (str != undefined && str.substring != undefined && str.indexOf != undefined) {

+                var strpos = str.indexOf("]"); 

+                text = str.substring(strpos+1);

+                var color = str.substring(str.indexOf(":")+1, strpos);

+                if (v_led != color) {

+                    v_led = color;

+                    $("#" + v_mainId + " img").attr("src", getImg(v_led));

+                }

+            }

+            

+            if (v_customData.isLabelPresent !== false) {

+                $("#" + v_mainId + "_label").text(v_customData.labelText == undefined ? text : v_customData.labelText);

+            }

+            

+            ViewUtils.addTooltip(v_mainId, v_customData);

+        }

+    };

+

+    function getHtml() {

+        var html = '<div id="' + v_mainId + '"><span>';

+        var img = '<img src="">';

+        var label = '';

+        

+        if (v_customData.isLabelPresent !== false) {

+            label += '<label id="' + v_mainId + '_label">';

+            if (v_customData.labelText != undefined) {

+                label += v_customData.labelText;

+            }

+            label += '</label>';

+        }

+        

+        if (v_customData.alignment == "right") {

+            html += label;

+            html += img;

+        } else {

+            html += img;

+            html += label;

+        }

+        

+        html += '</span></div>';

+        return html;

+    }

+    

+    function getImg(ledColor) {

+        var img = "";

+        switch (ledColor) {

+            case "blue":

+                img = "WebApplicationFramework/Res/blueLED.png";

+                break;

+            case "black":

+                img = "WebApplicationFramework/Res/blackLED.png";

+                break;

+            case "yellow":

+                img = "WebApplicationFramework/Res/yellowLED.png";

+                break;

+            case "green":

+                img = "WebApplicationFramework/Res/greenLED.png";

+                break;

+            case "red":

+                img = "WebApplicationFramework/Res/redLED.png";

+                break;

+            case "spinning":

+                img = "WebApplicationFramework/Res/waiting.gif";

+                break;

+        }

+        return img;

+    }

+}

+

+CView_StatusLED.getHelp = function() {

+    return "Visual element for status LEDs";

+};

+

+CView_StatusLED.expectsInterface = function() {

+    return [

+        {

+            "mandatory": ["getListWithElementInfo"]

+        },

+        {

+            "optional": ["getState"]

+        }

+    ];

+};

+

+CView_StatusLED.getCustomDataSchema = function() {

+    var schema = {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "title": "Custom data for CView_StatusLED",

+        "type": "object",

+        "properties": {

+            "isLabelPresent": {

+                "type": "boolean",

+                "format": "checkbox",

+                "default": false,

+                "description": "show status led as text (default true)"

+            },

+            "labelText": {

+                "type": "string",

+                "description": "show this text istead of the status led text"

+            },

+            "alignment": {

+                "type": "string",

+                "enum": ["left", "right"],

+                "default": "right",

+                "description": "the position of the image relative to the label (default left)"

+            }

+        },

+        "additionalProperties": false

+    };

+    $.extend(true, schema, ViewUtils.commonViewSchema, ViewUtils.commonElementSchema);

+    return schema;

+};

+//# sourceURL=WebApplicationFramework\Views\View_StatusLED.js

diff --git a/htdocs/WebApplicationFramework/Views/View_Table_Vertical.css b/htdocs/WebApplicationFramework/Views/View_Table_Vertical.css
new file mode 100644
index 0000000..175824d
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Table_Vertical.css
@@ -0,0 +1,134 @@
+.ElementTable_Vertical,
+.TableGray_Vertical {
+    width: 100%;
+    height: 100%;
+    white-space: nowrap;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+}
+
+.ElementTable_Vertical_HeaderBar,
+.TableGray_Vertical_HeaderBar {
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+    width: 100%;
+    overflow: hidden;
+    padding-left: 2px;
+    white-space: nowrap;
+    border-bottom: 1px solid black;
+}
+
+.ElementTable_Vertical_HeaderBar {
+    background-color: #55BAD4;
+}
+
+.TableGray_Vertical_HeaderBar {
+    background-color: #888888;
+}
+
+.ElementTable_Vertical_HeaderBar > *,
+.TableGray_Vertical_HeaderBar > * {
+    display: inline-block;
+    vertical-align: middle;
+    overflow: hidden;
+    white-space: nowrap;
+}
+
+.ElementTable_Vertical_Name,
+.TableGray_Vertical_Name {
+    width: 50%;
+    font-weight: bold;
+}
+
+.ElementTable_Vertical_SearchLabel,
+.TableGray_Vertical_SearchLabel {
+    width: 15%;
+    text-align: right;
+    float: right;
+}
+
+.ElementTable_Vertical_SearchInput,
+.TableGray_Vertical_SearchInput {
+    width: 35%;
+    float: right;
+}
+
+.ElementTable_Vertical_TableWrapper,
+.TableGray_Vertical_TableWrapper {
+    overflow-y: auto;
+}
+
+.ElementTable_Vertical table,
+.TableGray_Vertical table {
+    width: 100%;
+}
+
+.ElementTable_Vertical table tbody tr td.ElementTable_Vertical_Selected {
+    background-color: #66a19f;
+}
+
+.TableGray_Vertical table tbody tr td.ElementTable_Vertical_Selected {
+    background-color: #4CAF50;
+    color: white;
+}
+
+.ElementTable_Vertical table,
+.TableGray_Vertical table {
+    border: none;
+    border-collapse: collapse;
+}
+
+.ElementTable_Vertical table tbody tr th.ElementTable_Vertical_Header,
+.TableGray_Vertical table tbody tr th.TableGray_Vertical_Header {
+    color: black;
+    font-weight: bold;
+    /*font-size: 14px;*/
+    text-align: left;
+    padding: 2px;
+    border-right: 1px solid black;
+}
+
+.ElementTable_Vertical table tbody tr th.ElementTable_Vertical_Header {
+    background-color: #66CBE5;
+}
+
+.TableGray_Vertical table tbody tr th.TableGray_Vertical_Header {
+    background-color: #8D8D8D;
+}
+
+.ElementTable_Vertical_Sort_No,
+.ElementTable_Vertical_Sort_Asc,
+.ElementTable_Vertical_Sort_Desc,
+.TableGray_Vertical_Sort_No,
+.TableGray_Vertical_Sort_Asc,
+.TableGray_Vertical_Sort_Desc {
+    background-position: right center;
+    background-repeat: no-repeat;
+}
+.ElementTable_Vertical_Sort_Asc,
+.TableGray_Vertical_Sort_Asc {
+    background-image: url("WebApplicationFramework/Res/sort_asc.png");
+}
+.ElementTable_Vertical_Sort_Desc,
+.TableGray_Vertical_Sort_Desc {
+    background-image: url("WebApplicationFramework/Res/sort_desc.png");
+}
+.ElementTable_Vertical_Sort_No,
+.TableGray_Vertical_Sort_No {
+    background-image: url("WebApplicationFramework/Res/sort_both.png");
+}
+
+.ElementTable_Vertical tr td {
+    xheight: 30px;
+    padding: 2px 2px;
+    /*font-size: 12px;*/
+    background-color: #F2FBFD;
+    color: black;
+}
+
+.TableGray_Vertical tr td {
+    padding: 2px 2px;
+    background-color: #c5c5c5;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Table_Vertical.js b/htdocs/WebApplicationFramework/Views/View_Table_Vertical.js
new file mode 100644
index 0000000..2bb65e9
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Table_Vertical.js
@@ -0,0 +1,477 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_Table_Vertical(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+
+    /** constructor */
+
+    var v_viewmodels = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_Table_Vertical);
+    this.dataViewmodel = v_viewmodels[0];
+    this.sortViewmodel = v_viewmodels[1];
+    var v_conditionViewmodel = v_viewmodels[2];
+
+    var v_parentId = p_parentId;
+    this.mainId = p_mainId;
+    this.tableWrapperId = this.mainId + "_TableWrapper";
+    this.tableId = this.mainId + "_Table";
+    this.customData = p_data;
+    this.subViewDescriptors;
+
+    this.mainClass = "ElementTable_Vertical";
+    if (this.customData.class != undefined) {
+        this.mainClass = this.customData.class;
+    }
+
+    var v_currentTableData = {
+        "selection": [],
+        "table": [],
+        "separators": []
+    };
+    var v_currentHeader = [];
+    this.subViews = [];
+
+    var v_this = this;
+
+    /** public functions */
+
+    this.applicationCreated = function() {
+        if (v_this.dataViewmodel != undefined) {
+            createTable();
+            setupCallbacks();
+        }
+    };
+
+    this.refresh = function(p_fullRefresh) {
+        if (v_this.dataViewmodel != undefined) {
+            if (ViewUtils.checkVisibility(v_conditionViewmodel, v_this.mainId)) {
+                var newTableData = v_this.dataViewmodel.getTable();
+                if (newTableData == undefined || newTableData.table == undefined) {
+                    return;
+                }
+                if (v_this.sortViewmodel != undefined) {
+                    newTableData = v_this.sortViewmodel.getAlteredData(newTableData);
+                }
+                if (newTableData.separators == undefined) {
+                    newTableData.separators = [];
+                }
+
+                var newSeparatorsNeeded = JSON.stringify(v_currentTableData.separators) != JSON.stringify(newTableData.separators);
+                // we remove the existing separators
+                if (newSeparatorsNeeded) {
+                    $("#" + v_this.mainId + " ." + v_this.mainClass + "_Separator").remove();
+                }
+
+                if (p_fullRefresh && !headerEquals(v_this.dataViewmodel.getHeader(), v_currentHeader)) {
+                    v_currentHeader = v_this.dataViewmodel.getHeader();
+                    createSubviewList();
+                    destroyTableData();
+                    v_this.createHeader(v_currentHeader);
+                    v_this.addDataToTable(newTableData.table.length, v_currentHeader.length);
+                } else if (newTableData.table.length != v_currentTableData.table.length) {
+                    // If new table has more rows, the number will be positive, so we add as many rows. If it is negative, we remove the rows.
+                    // This can be made protected, so the vertical table will only have to override this function... and a few others
+                    v_this.addDataToTable(newTableData.table.length - v_currentTableData.table.length, v_currentHeader.length);
+                }
+
+                v_currentTableData = newTableData;
+
+                if (newSeparatorsNeeded) {
+                    v_this.createSeparators(v_currentTableData.separators);
+                }
+
+                for (var i = 0; i < v_this.subViews.length; ++i) {
+                    for (var j = 0; j < v_this.subViews[i].length; ++j) {
+                        // if we have a subview instance, we refresh it, or we simply update the content of the cell
+                        if (v_this.subViews[i][j] != undefined && v_this.subViews[i][j].refresh != undefined) {
+                            v_this.subViews[i][j].refresh(p_fullRefresh);
+                        } else {
+                            updateCell(i,j);
+                        }
+                    }
+                }
+
+                v_this.setSelection(newTableData.selection);
+                setSearchAndFilter();
+
+                //setHeight();
+            }
+        }
+    };
+
+    /** protected functions */
+
+    this.setSelection = function(selection) {
+        $("#" + v_this.tableId + " tbody tr td").removeClass(v_this.mainClass + "_Selected");
+        if (selection != undefined) {
+            for (var i = 0; i < selection.length; ++i) {
+                $("#" + v_this.tableId + " tbody tr td:nth-child(" + (selection[i] + 2) + ")").addClass(v_this.mainClass + "_Selected");
+            }
+        }
+    };
+
+    this.addDataToTable = function(p_numberOfRows, p_numberOfColumns) {
+        var numberOfRows = $("#" + v_this.tableId + " tbody tr:first td").length;
+        if (p_numberOfRows > 0) {
+
+            var rows = $("#" + v_this.tableId + " tbody tr");
+
+            for (var j = 0; j < p_numberOfColumns; ++j) {
+                var html = '';
+                for (var i = 0; i < p_numberOfRows; ++i) {
+                    html += '<td id="' + v_this.tableId + "_SubView_" + (numberOfRows + i) + "_" + j + '"></td>';
+                }
+                $(rows[j]).append(html);
+            }
+
+            // create the subviews where applicable
+
+            for (var i = 0; i < p_numberOfRows; ++i) {
+                var subViews = [];
+                for (var j = 0; j < p_numberOfColumns; ++j) {
+                    if (v_this.subViewDescriptors != undefined && v_this.subViewDescriptors[j] != undefined && v_this.subViewDescriptors[j].subView != undefined && window[v_this.subViewDescriptors[j].subView] != undefined) {
+                        var parentId = v_this.tableId + "_SubView_" + (numberOfRows + i) + "_" + j;
+                        var viewId = v_this.tableId + "_SubView_" + (numberOfRows + i) + "_" + j + "_View";
+                        var viewmodel = new v_this.ViewmodelProxy(numberOfRows + i, j);
+
+                        var subView = new window[v_this.subViewDescriptors[j].subView]([viewmodel], viewId, parentId, v_this.subViewDescriptors[j]);
+                        subView.applicationCreated();
+                        ViewUtils.applyCss(v_this.subViewDescriptors[j], viewId);
+                        ViewUtils.processCss(v_this.subViewDescriptors[j], parentId);
+                        subViews.push(subView);
+                    } else {
+                        // we must ensure that there are as many subviews as the number of cells in the table
+                        subViews.push(null);
+                    }
+                }
+                v_this.subViews.push(subViews);
+            }
+        } else {
+            for (var i = 0; i > p_numberOfRows; --i) {
+                v_this.subViews.pop();
+            }
+            // we remove the correct number of rows from the DOM and the subviews
+            $("#" + v_this.tableId + " tbody tr").each(function() {
+                $(this).find("td").slice(numberOfRows + p_numberOfRows).remove();
+            });
+        }
+    };
+
+    this.createHeader = function(p_headerList) {
+        var html = '';
+        for (var i = 0; i < p_headerList.length; ++i) {
+            html += '<tr><th>' + p_headerList[i].heading + '</th></tr>';
+        }
+
+        $("#" + v_this.tableId).append(html);
+        var firstCol = $("#" + v_this.tableId + " tbody tr th");
+        firstCol.addClass(v_this.mainClass + "_Header");
+
+        if (v_this.customData.displayHeader === false) {
+            firstCol.css("display", "none");
+        }
+    };
+
+    this.createSeparators = function(separators) {
+        // nothing to do yet
+    };
+
+    this.setupSelection = function() {
+        $("#" + v_this.tableId).on("click", "td", function() {
+            var index = $(this).index() - 1;
+            if (index >= 0) {
+                v_this.dataViewmodel.select(v_this.getUnalteredIndex(index));
+            }
+        });
+    };
+
+    this.getUnalteredIndex = function(index) {
+        if (v_this.sortViewmodel != undefined) {
+            return v_this.sortViewmodel.getUnalteredIndex(index);
+        } else {
+            return index;
+        }
+    };
+
+    this.displayFilter = function() {
+        return v_this.sortViewmodel != undefined && v_this.customData.filter !== false;
+    };
+
+    this.displaySort = function() {
+        return v_this.sortViewmodel != undefined && v_this.customData.sort === true;
+    };
+
+    this.getIndexOfTableHeaderBasedOnOrientation = function(obj) {
+        return obj.parent().index();
+    };
+
+    /** private functions */
+
+    function updateCell(p_row, p_col) {
+
+        if (v_currentTableData.table[p_row][p_col] == undefined) {
+            $("#" + v_this.tableId + "_SubView_" + p_row + "_" + p_col).addClass("NoData");
+            $("#" + v_this.tableId + "_SubView_" + p_row + "_" + p_col).html("");
+        } else {
+            $("#" + v_this.tableId + "_SubView_" + p_row + "_" + p_col).removeClass("NoData");
+            $("#" + v_this.tableId + "_SubView_" + p_row + "_" + p_col).html(v_currentTableData.table[p_row][p_col].val);
+        }
+    }
+    /*
+    function setHeight() {
+        if (v_this.customData.autoHeight != true) {
+            if (v_this.customData.displayName !== false || v_this.displayFilter()) {
+                $("#" + v_this.tableWrapperId).height("" + ( $("#" + v_this.mainId).innerHeight() - $("#" + v_this.mainId + " ." + v_this.mainClass + '_HeaderBar').outerHeight() ) + "px");
+            } else {
+                $("#" + v_this.tableWrapperId).height("100%");
+            }
+        }
+    }
+    */
+    function createSubviewList() {
+        if (v_this.customData.columns != undefined) {
+            v_this.subViewDescriptors = [];
+            for (var i = 0; i < v_currentHeader.length; ++i) {
+                if (v_currentHeader[i].elementIndex != undefined && v_this.customData.columns[v_currentHeader[i].elementIndex] != undefined) {
+                    v_this.subViewDescriptors.push(v_this.customData.columns[v_currentHeader[i].elementIndex]);
+                }
+            }
+        }
+    }
+
+    function setSearchAndFilter() {
+        if (v_this.displaySort()) {
+            var headers = $("#" + v_this.tableId + " tbody tr th");
+            headers.removeClass(v_this.mainClass + "_Sort_Asc");
+            headers.removeClass(v_this.mainClass + "_Sort_Desc");
+            headers.addClass(v_this.mainClass + "_Sort_No");
+
+            var currentSort = v_this.sortViewmodel.getSort();
+            if (currentSort != undefined) {
+                if (currentSort.sortDirection == "asc") {
+                    $(headers[currentSort.sortBy]).removeClass(v_this.mainClass + "_Sort_No").addClass(v_this.mainClass + "_Sort_Asc");
+                } else if (currentSort.sortDirection == "desc") {
+                    $(headers[currentSort.sortBy]).removeClass(v_this.mainClass + "_Sort_No").addClass(v_this.mainClass + "_Sort_Desc");
+                }
+            }
+        }
+
+        if (v_this.displayFilter()) {
+            var inputBox = $("#" + v_this.mainId + " ." + v_this.mainClass + "_SearchInput");
+            var currentVal = inputBox.val();
+            var newVal = v_this.sortViewmodel.getFilter();
+            if (newVal != currentVal) {
+                inputBox.val(newVal);
+            }
+        } else {
+            $("#" + v_this.mainId + " ." + v_this.mainClass + "_Name").width("100%");
+        }
+    }
+
+    function headerEquals(header1, header2) {
+        return JSON.stringify(header1) == JSON.stringify(header2);
+    }
+
+    function destroyTableData() {
+        $("#" + v_this.tableId).empty();
+        v_this.subViews = [];
+    }
+
+    function createTable() {
+        var html = '<div id="' + v_this.mainId + '">' +
+            '<div class="' + v_this.mainClass + '_HeaderBar">' +
+                '<label class="' + v_this.mainClass + '_Name">' + getName() + '</label>' +
+                '<label class="' + v_this.mainClass + '_SearchLabel">Search:</label>' +
+                '<input class="' + v_this.mainClass + '_SearchInput"></input>' +
+            '</div>' +
+            '<div class="' + v_this.mainClass + '_TableWrapper" id="' + v_this.tableWrapperId + '">' +
+                '<table id="' + v_this.tableId +'"></table>' +
+            '</div>' +
+        '</div>';
+
+        $("#" + v_parentId).append(html);
+        $("#" + v_this.mainId).addClass(v_this.mainClass);
+
+        if (v_this.customData.displayName === false && !v_this.displayFilter()) {
+            $("#" + v_this.mainId + " ." + v_this.mainClass + "_HeaderBar").css("display", "none");
+        } else if (!v_this.displayFilter()) {
+            $("#" + v_this.mainId + " ." + v_this.mainClass + "_SearchLabel").css("display", "none");
+            $("#" + v_this.mainId + " ." + v_this.mainClass + "_SearchInput").css("display", "none");
+        }
+    }
+
+    function getName() {
+        if (v_this.customData.displayName === false) {
+            return "";
+        } else {
+            if (v_this.customData.name != undefined) {
+                return v_this.customData.name;
+            } else {
+                return v_this.dataViewmodel.getName();
+            }
+        }
+    }
+
+    function setupCallbacks() {
+        v_this.setupSelection();
+        setupSortAndFilter();
+    }
+
+    function setupSortAndFilter() {
+        if (v_this.displayFilter()) {
+            $("#" + v_this.mainId + " ." + v_this.mainClass + "_SearchInput").on("input", function(event) {
+                v_this.sortViewmodel.setFilter(event.currentTarget.value);
+            });
+        }
+
+        if (v_this.displaySort()) {
+            $("#" + v_this.tableId).on("click", "th", function() {
+                var obj = $(this);
+                if (obj.hasClass(v_this.mainClass + "_Sort_Asc")) {
+                    v_this.sortViewmodel.setSort({
+                        "sortBy": v_this.getIndexOfTableHeaderBasedOnOrientation(obj),
+                        "sortDirection": "desc"
+                    });
+                } else if (obj.hasClass(v_this.mainClass + "_Sort_Desc")) {
+                    v_this.sortViewmodel.setSort(undefined);
+                } else {
+                    v_this.sortViewmodel.setSort({
+                        "sortBy": v_this.getIndexOfTableHeaderBasedOnOrientation(obj),
+                        "sortDirection": "asc"
+                    });
+                }
+            });
+        }
+    }
+
+    /** protected classes */
+
+    this.ViewmodelProxy = function(p_row, p_col) {
+
+        var v_row = p_row;
+        var v_col = p_col;
+
+        this.select = v_this.dataViewmodel.select;
+
+        this.getList = function() {
+            return {
+                "selections": [v_currentTableData.selection],
+                "values": [[v_currentTableData.table[v_row][v_col].val], undefined, v_currentTableData.table[v_row][v_col].isWritable]
+            };
+        };
+
+        this.getListWithElementInfo = function() {
+            return {
+                "selections": [v_currentTableData.selection],
+                "values": [
+                    {
+                        "element": v_currentHeader[v_col].heading,
+                        "val": v_currentTableData.table[v_row][v_col].val,
+                        "isWritable": v_currentTableData.table[v_row][v_col].isWritable
+                    }
+                ]
+            };
+        };
+
+        this.setValue = function(p_dataPathIndex, p_value, p_indexInList, p_lastSelectionIndexes, p_callback, p_additionalData) {
+            v_this.dataViewmodel.setValue(v_this.getUnalteredIndex(v_row), v_col, p_value, p_callback, p_additionalData);
+        };
+
+        this.getState = function() {
+            return v_currentTableData.table[v_row][v_col].tp != 0;
+        };
+
+        this.getDataList = v_this.dataViewmodel.getDataList;
+    };
+}
+
+CView_Table_Vertical.getHelp = function() {
+    return "A table view whose rows can contain single element subviews.\n" +
+        "It reguires a table viewmodel. Optionally, a sort and filter viewmodel can be connected to this view.";
+};
+
+CView_Table_Vertical.expectsInterface = function() {
+    return [
+        {
+            "mandatory": ["select", "getName", "getHeader", "getTable", "setValue"],
+        },
+        {
+            "optional": ["getAlteredData", "getFilter", "getSort", "setFilter", "setSort", "getUnalteredIndex"]
+        },
+        {
+            "optional": ["getState"]
+        }
+    ];
+};
+
+CView_Table_Vertical.getCustomDataSchema = function() {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CView_Table_Vertical",
+        "type": "object",
+        "properties": {
+            "class": {
+                "description": "The css class of the table",
+                "type": "string",
+                "default": "ElementTableVertical"
+            },
+            "displayName": {
+                "description": "Whether we display the table name (default true)",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": false
+            },
+            "displayHeader": {
+                "description": "Whether we display the table header bar (default true)",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": false
+            },
+            "autoHeight": {
+                "description": "Whether the table will take up as much vertical space as needed (default false: takes up only the available space). Use true if the height of the parent is unknown.",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            },
+            "filter": {
+                "description": "Whether we allow filtering (default true)",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": false
+            },
+            "sort": {
+                "description": "Whether we allow sorting",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            },
+            "name": {
+                "description": "The table name",
+                "type": "string"
+            },
+            "columns": {
+                "description": "The columns of the table can contain single element subviews. The name of the subview, the flex of the column and the custom data of the subview can be specified in an item.",
+                "type": "array",
+                "format": "tabs",
+                "items": {
+                    "type": "object",
+                    "title": "subView",
+                    "properties": {
+                        "subView" : {
+                            "type" : "string",
+                            "description": "the class name of the subview"
+                        }
+                    },
+                    "additionalProperties": true
+                }
+            }
+        },
+        "additionalProperties": false
+    };
+    $.extend(true, schema, ViewUtils.commonViewSchema);
+    return schema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_Table_Vertical.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Tabs.css b/htdocs/WebApplicationFramework/Views/View_Tabs.css
new file mode 100644
index 0000000..73d89aa
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Tabs.css
@@ -0,0 +1,20 @@
+.TabsView {
+    width: 100%;
+    height: 100%;
+    box-sizing: border-box;
+}
+
+.TabsView > ul {
+    box-sizing: border-box;
+    height: 25px;
+    padding: 0;
+    margin: 0;
+    border-bottom: 2px solid #f1f1f1;
+    background-color: #d5d5d5;
+}
+
+.TabsView.ui-tabs > .ui-tabs-panel {
+    box-sizing: border-box;
+    height: calc(100% - 25px);
+    padding: 0;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_Tabs.js b/htdocs/WebApplicationFramework/Views/View_Tabs.js
new file mode 100644
index 0000000..92ca933
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Tabs.js
@@ -0,0 +1,103 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_Tabs(aViewModels, aID, aParentID, aCustomData)

+{

+    "use strict";

+    

+	/** private members and constructor */

+    var mViewModel = ViewUtils.getViewmodelsFromExpectedInterface(aViewModels, CView_Tabs)[0];

+    var mID = aID;

+    var mParentID = aParentID;

+    var mCustomData = aCustomData;

+    var mThis = this;

+    var mTabs;

+    

+    var mActivateCallback = true;

+

+	/** public functions */

+    this.applicationCreated = function() 

+    {

+        createHTML();

+    };

+

+    this.refresh = function(aFullRefresh) {

+        if (mViewModel && mViewModel.getList)

+        {

+            var selections = mViewModel.getList().selections[0];

+            mActivateCallback = false;

+            mTabs.tabs('option', 'active', selections[0]);

+            mActivateCallback = true;

+        }

+    };

+    

+    /** private functions */

+    function createHTML()

+    {

+        var lHtml = '<div id="' + mID + '" class="TabsView"><ul>';

+

+        for (var i = 0; i < mCustomData.idsCreating.length; ++i)

+        {

+            var lName = undefined; 

+            if (mCustomData.namesCreating)

+                lName = mCustomData.namesCreating[i];

+            if (!lName)

+                lName = mCustomData.idsCreating[i];

+            lHtml += '<li><a href="#' + mCustomData.idsCreating[i] + '">' + lName + '</a></li>';

+        }

+        

+        lHtml += '</ul>';

+        

+        for (var i = 0; i < mCustomData.idsCreating.length; ++i)

+            lHtml += '<div id="' + mCustomData.idsCreating[i] + '"></div>';

+        

+        lHtml += '</div>';

+

+        $("#" + mParentID).append(lHtml);

+        mTabs = $('DIV#' + mID).tabs({

+            activate: function(ev, ui) {

+                if (mActivateCallback && mViewModel && mViewModel.select)

+                    mViewModel.select(ui.newTab.index());

+            }

+        });

+    }

+}

+

+CView_Tabs.getHelp = function() {

+    return "A tab view that creates static tabs.\n" +

+        "If a viewmodel is connected, its selection will be used to show the active tab and its select method will be used when switching tabs.\n" +

+        "As many subviews can be connected to this view as the number of tabs that are created.";

+};

+

+CView_Tabs.expectsInterface = function() {

+    return [{

+        "optional": ["getList", "select"]

+    }];

+}

+

+CView_Tabs.getCustomDataSchema = function() {

+    var schema = {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "title": "Custom data for CView_Tabs",

+        "type": "object",

+        "properties": {

+            "namesCreating": {

+                "description": "The name of the tabs that are created.",

+                "type": "array",

+                "format": "table",

+                "items": {

+                    "type": "string",

+                    "title": "tab"

+                },

+                "minItems": 1

+            }

+        },

+        "additionalProperties": false

+    };

+    $.extend(true, schema, ViewUtils.commonViewSchema);

+    return schema;

+};

+

+//# sourceURL=WebApplicationFramework\Views\View_Tabs.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_TabsWithData.css b/htdocs/WebApplicationFramework/Views/View_TabsWithData.css
new file mode 100644
index 0000000..19f2848
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_TabsWithData.css
@@ -0,0 +1,88 @@
+.TabsWithData {
+    background-color: #f1f1f1;
+    height: 100%;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+}
+.TabsWithData_Vertical_Tabs {
+    display: inline-block;
+    width: 10%;
+    height: 100%;
+    vertical-align:top;
+    background-color: #d5d5d5;
+    border-right: 2px solid #f1f1f1;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+    overflow: hidden;
+}
+.TabsWithData_Vertical_Ul {
+    list-style-type: none;
+    margin: 0;
+    padding: 0;
+    width: 100%;
+    height: 100%;
+}
+.TabsWithData_Vertical_Li {
+    display: block;
+    color: #000;
+    background-color: #c5c5c5;
+    padding: 6px 0 6px 6px;
+    text-decoration: none;
+    cursor:pointer;
+}
+.TabsWithData_Vertical_Panel {
+    display: inline-block;
+    width: 90%;
+    height: 100%;
+    vertical-align:top;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+}
+
+.TabsWithData_Horizontal_Tabs {
+    display: block;
+    width: 100%;
+    background-color: #d5d5d5;
+    border-bottom: 2px solid #f1f1f1;
+    vertical-align:top;
+    overflow: hidden;
+    height: 25px;
+    box-sizing: border-box;
+}
+.TabsWithData_Horizontal_Ul {
+    list-style-type: none;
+    margin: 0;
+    padding: 0;
+    overflow: hidden;
+}
+.TabsWithData_Horizontal_Li {
+    float: left;
+    display: inline-block;
+    color: #000;
+    background-color: #c5c5c5;
+    text-align: center;
+    padding: 6px 6px;
+    text-decoration: none;
+    cursor:pointer;
+}
+.TabsWithData_Horizontal_Panel {
+    display: block;
+    width: 100%;
+    height: calc(100% - 27px);
+    vertical-align:top;
+    box-sizing: border-box;
+}
+
+.TabsWithData_Horizontal_Li:hover,
+.TabsWithData_Vertical_Li:hover {
+    background-color: #999;
+    color: white;
+}
+
+.TabsWithData_Selected {
+    background-color: #4CAF50;
+    color: white;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/Views/View_TabsWithData.js b/htdocs/WebApplicationFramework/Views/View_TabsWithData.js
new file mode 100644
index 0000000..ff24b67
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_TabsWithData.js
@@ -0,0 +1,139 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_TabsWithData(p_viewmodels, p_mainId, p_parentId, p_data) {
+    "use strict";
+    
+    /** constructor */
+    
+    var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_TabsWithData)[0];
+    var v_conditionViewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_TabsWithData)[1];
+    var v_mainId = p_mainId;
+    var v_parentId = p_parentId;
+    var v_customData = p_data;
+    if (v_customData.class == undefined) {
+        v_customData.class = "TabsWithData";
+    }
+    
+    var v_this = this;
+    
+    /** public functions */
+
+    this.applicationCreated = function() {
+        if (v_viewmodel != undefined) {
+            $("#" + v_parentId).append(getHtml(getOrientation()));
+            setupCallbacks();
+        }
+    };
+
+    this.refresh = function(p_fullRefresh) {
+        if (v_viewmodel != undefined && ViewUtils.checkVisibility(v_conditionViewmodel, v_mainId)) {
+            var dataObject = v_viewmodel.getList();
+            if (p_fullRefresh) {
+                fullRefresh(dataObject, getOrientation());
+            } else {
+                setSelection(dataObject);
+                setText(dataObject);
+            }
+        }
+    };
+
+    /** private functions */
+    
+    function fullRefresh(dataObject, orientation) {
+        var data = dataObject.values[0];
+        var ul = $("#" + v_mainId + "_ul");
+        ul.empty();
+        
+        for (var i = 0; i < data.length; ++i) {
+            ul.append('<li class="' + v_customData.class + '_' + orientation + '_Li">' + data[i][0] + '</li>');
+        }
+        
+        setSelection(dataObject);
+    }
+
+    function setSelection(dataObject) {
+        if (dataObject.selections[0] != undefined) {
+            var selected = dataObject.selections[0][0];
+            if (selected != undefined) {
+                $("#" + v_mainId + "_ul li").removeClass(v_customData.class + "_Selected");
+                $('#' + v_mainId + "_ul li:nth-child(" + (selected + 1) + ")").addClass(v_customData.class + "_Selected");
+            }
+        } else {
+            $("#" + v_mainId + "_ul li").removeClass(v_customData.class + "_Selected");
+        }
+
+    }
+    
+    function setText(dataObject) {
+        var list = $("#" + v_mainId + "_ul li");
+        for (var i = 0; i < Math.min(list.length, dataObject.values[0].length); ++i) {
+            $(list[i]).text(dataObject.values[0][i][0]);
+        }
+    }
+    
+    function getOrientation() {
+        if (v_customData.orientation != undefined && v_customData.orientation.toLowerCase() == "vertical") {
+            return "Vertical";
+        } else {
+            return "Horizontal";
+        }
+    }
+    
+    function getHtml(orientation) {
+        return '' +
+            '<div class="' + v_customData.class + '" id="' + v_mainId + '">' +
+                '<div class="' + v_customData.class + '_' + orientation + '_Tabs">' +
+                    '<ul id="' + v_mainId + "_ul" + '" class="' + v_customData.class + '_' + orientation + '_Ul"></ul>' +
+                '</div>' +
+                '<div id="' + v_customData.idsCreating[0] + '" class="' + v_customData.class + '_' + orientation + '_Panel">' + 
+            '</div>';
+    }
+
+    function setupCallbacks() {
+        $('#' + v_mainId + "_ul").on('click', 'li', function() {
+            v_viewmodel.select($(this).index());
+        });
+    }
+}
+
+CView_TabsWithData.getHelp = function() {
+    return "A tab view that can have one connected subview and it can either be horizontally or vertically alligned.\n" +
+        "It will create as many tabs as returned by a connected viewmodel's getList function.";
+};
+
+CView_TabsWithData.expectsInterface = function() {
+    return [{
+        "mandatory": ["getList", "select"]
+    }, {
+        "optional": ["getState"]
+    }];
+}
+
+CView_TabsWithData.getCustomDataSchema = function() {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CView_TabsWithData",
+        "type": "object",
+        "properties": {
+            "orientation": {
+                "description": "The orientation of the tabs (default horizontal)",
+                "type": "string",
+                "enum": ["horizontal", "vertical"],
+                "default": "vertical"
+            },
+            "class": {
+                "description": "The css class of the tabs",
+                "type": "string",
+                "default": "TabsWithData"
+            }
+        },
+        "additionalProperties": false
+    };
+    $.extend(true, schema, ViewUtils.commonViewSchema);
+    return schema;
+};
+
+//# sourceURL=WebApplicationFramework\Views\View_TabsWithData.js
diff --git a/htdocs/WebApplicationFramework/Views/View_Test.css b/htdocs/WebApplicationFramework/Views/View_Test.css
new file mode 100644
index 0000000..0942a6c
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Test.css
@@ -0,0 +1,21 @@
+.alma {

+    color: green;

+}

+

+.testContainer {

+    display: flex;

+    flex-direction: row;

+    flex-wrap: wrap;

+}

+

+.testColumn{

+    padding: 3px;

+    border-right: 1px solid black;

+}

+

+.testCell{

+    border: 1px solid black;

+    display: inline-block;

+    margin: 1px;

+}

+

diff --git a/htdocs/WebApplicationFramework/Views/View_Test.js b/htdocs/WebApplicationFramework/Views/View_Test.js
new file mode 100644
index 0000000..80c6b91
--- /dev/null
+++ b/htdocs/WebApplicationFramework/Views/View_Test.js
@@ -0,0 +1,187 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView_Test(aViewModels, aID, aParentID)

+{

+    "use strict";

+    

+	/** private members and constructor */

+    var mViewModel = aViewModels[0];

+    var mID = aID;

+    var mDataTable = null;

+    var mParentID = aParentID;

+    var mThis = this;

+    var mEditList = [];

+    var lIDCounter;

+

+	/** public functions */

+    this.applicationCreated = function() {

+       // if (mViewModel.getOptions) {

+            var lOptions;// = mViewModel.getOptions();

+            createHtml(lOptions);

+            setupView(mID, lOptions);

+        // }

+        /*function htmlLoaded(aSucc, aData)

+        {

+            console.log("aData", aData);

+        }

+        mViewModel.loadFile("WebApplications/CustomizableApp/Views/View_Test.html", htmlLoaded);*/

+    };

+

+    this.refresh = function(aFullRefresh)

+    {

+        if (mViewModel.getListWithElementInfo) {

+            var lValueList = mViewModel.getListWithElementInfo(); //console.log(lValueList);

+            lIDCounter = 0;

+            //console.log (lValueList);

+

+            var lIsEqualStructure = true; // TODO NOWX - this is not working currently well

+            

+            if (aFullRefresh)

+            {

+                $('#' + mID).html('');

+                $('#' + mID).addClass("alma");

+                mEditList = []; 

+            }

+            for (var j = 0; j < lValueList.values.length; ++j)

+            {

+                var lObj = lValueList.values[j];

+                if (lObj)

+                {

+                    if (aFullRefresh)

+                    {

+                        var i = 0;

+                        var lContainer = document.createElement("DIV");

+                        lContainer.className = "testContainer";

+                        createColumn(lContainer, lObj, mID + "_" + j + "_" + (i++), true, j);

+                        if (lObj.children) 

+                        {

+                            for (var k = 0; k < lObj.children.length; ++k)

+                            {

+                                createColumn(lContainer, lObj.children[k], mID + "_" + j + "_" + (i++), false, j);

+                            }

+                        }

+                        $('#' + mID).append(lContainer);

+                        $('#' + mID).append('<div class=line></div>');

+                    }

+                    else

+                    { 

+                        refreshColumn(lObj);

+                        if (lObj.children) 

+                        {

+                            for (var k = 0; k < lObj.children.length; ++k)

+                            {

+                                refreshColumn(lObj.children[k]);

+                            }

+                        }

+                    }

+                }

+            }

+        }

+    };

+

+    /** private functions */

+    function action(e)

+    {

+        var lCklickedIndexInList = e.target.indexInList;

+        var lCklickedDataPathIndex = e.target.dataPathIndex;

+        if (lCklickedDataPathIndex != null)

+        {

+            var newVal = prompt("Please enter new value", e.target.innerHTML);

+            if (newVal != null)

+            {

+                mViewModel.setValue(lCklickedDataPathIndex, newVal, lCklickedIndexInList);

+            }            

+        }

+    }

+    function createHtml(aHeaderInfo)

+    {

+        var lDiv = document.createElement("DIV");

+        lDiv.innerHTML = '<div id='+mID+'></div>';

+        $("#" + mParentID).append(lDiv);

+        $('#' + mID).on('click', action);

+    }

+    

+    function createColumn(aParent, aObj, aId, aReadOnly, aDataPathIndex)

+    {

+        var lColumn = document.createElement("SPAN");

+        lColumn.className = "testColumn";

+        var lHeaderID = aId + '_header';

+        createCell(lColumn, aObj.element, true, lHeaderID, true);

+        if (Array.isArray(aObj.val)) {

+            for (var i = 0; i < aObj.val.length; ++i)

+            {

+                var lRowID = aId + '_row' + (i+1);

+                createCell(lColumn, aObj.val[i], aReadOnly, lRowID, true, aDataPathIndex, i);

+            }

+        } else {

+            var lRowID = aId + '_row_1';

+            createCell(lColumn, aObj.val, aReadOnly, lRowID, true, aDataPathIndex);

+        }

+        aParent.appendChild(lColumn);

+    }

+    

+    function refreshColumn(aObj)

+    {

+        refreshCell(aObj.element);

+        if (Array.isArray(aObj.val)) {

+            for (var i = 0; i < aObj.val.length; ++i)

+            {

+                refreshCell(aObj.val[i]);

+            }

+        } else {

+            refreshCell(aObj.val);

+        }

+    }

+    

+    function createCell(aParent, aArray, aReadOnly, aId, aBreak, aDataPathIndex, aIndexInList)

+    {

+        var lCell = document.createElement("SPAN");

+        if (aDataPathIndex != undefined) { lCell.dataPathIndex = aDataPathIndex; }

+        if (Array.isArray(aArray)) {

+            for (var l = 0; l < aArray.length; ++l) 

+            {

+                createCell(lCell, aArray[l], false, aId + "_" + l, false);

+            }

+            aParent.appendChild(lCell);

+            if (aBreak) { aParent.appendChild(document.createElement("br")); }

+        } else {

+            lCell.className = "testCell";

+            lCell.innerHTML = aArray;

+            lCell.readOnly = aReadOnly;

+            lCell.id = aId;

+            mEditList.push(lCell.id);

+            if (aIndexInList != undefined) { lCell.indexInList = aIndexInList; }

+            aParent.appendChild(lCell);

+            if (aBreak) { aParent.appendChild(document.createElement("br")); } 

+        }

+    }

+    

+    function refreshCell(aArray)

+    {

+        if (Array.isArray(aArray)) {

+            for (var l = 0; l < aArray.length; ++l) 

+            {

+                refreshCell(aArray[l]);

+            }

+        } else {

+            $('#' + mEditList[lIDCounter++]).html(aArray); 

+        }

+    }

+    

+    function setupView(aTableID, aOptions)

+    {

+    }

+    

+    function setupCallbacks(aTableID)

+    {

+    }

+}

+

+CView_Test.getHelp = function() {

+    return "A basic view that can show data using the cnnected viewmodel's getListWithElementInfo.";

+}

+

+//# sourceURL=WebApplicationFramework\Views\View_Test.js
\ No newline at end of file
diff --git a/htdocs/WebApplicationFramework/WebApp_Model.js b/htdocs/WebApplicationFramework/WebApp_Model.js
new file mode 100644
index 0000000..476bbc4
--- /dev/null
+++ b/htdocs/WebApplicationFramework/WebApp_Model.js
@@ -0,0 +1,74 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CWebApp_Model(p_fileHandler)

+{

+    "use strict";

+

+    var v_fileHandler = p_fileHandler;

+    var v_setupModel = new CSetup_Model(v_fileHandler);

+    var v_mainConfig = new JsonLoader("CustomizableContent/MainConfig.json", v_fileHandler, {});

+    var v_appConfig;

+    var v_this = this;

+

+    this.getFileHandler = function() {

+        return v_fileHandler;

+    };

+

+    this.getSetupModel = function() {

+        return v_setupModel;

+    };

+

+    this.loadMainConfig = function(callback) {

+        loadConfig(v_mainConfig, callback);

+    };

+

+    this.saveMainConfig = function(data, callback) {

+        saveConfig(v_mainConfig, data, callback);

+    };

+

+    this.getMainConfig = function() {

+        return getConfig(v_mainConfig);

+    };

+

+    this.loadAppConfig = function(filename, callback) {

+        v_appConfig = new JsonLoader(filename, v_fileHandler, {});

+        loadConfig(v_appConfig, callback);

+    };

+

+    this.saveAppConfig = function(data, callback) {

+        saveConfig(v_appConfig, data, callback);

+    };

+

+    this.getAppConfig = function() {

+        return getConfig(v_appConfig);

+    };

+

+    function loadConfig(config, callback) {

+        config.taskOperation(function(ok, data) {

+            if (ok) {

+                callback(data);

+            } else {

+                alert('Failed to load config: ' + config.getUrl());

+                callback({});

+            }

+        });

+    }

+

+    function saveConfig(config, data, callback) {

+        if (data) {

+            config.setData(data);

+        }

+        config.save(undefined, callback);

+    }

+

+    function getConfig(config) {

+        if (config != undefined) {

+            return config.getData();

+        } else {

+            return {};

+        }

+    }

+}
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/Main.js b/htdocs/WebApplications/CustomizableApp/Main.js
new file mode 100644
index 0000000..8fb13f8
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/Main.js
@@ -0,0 +1,264 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+/** Common functionality for applications, such as

+ - mainLoop,

+ - request issuing

+ - response comparison

+ - binding between view and viewModel */

+

+var WebApplications = WebApplications || [];

+

+WebApplications.push({'application': new CustomizableApp()});

+

+function CustomizableApp() {

+    "use strict";

+

+    var m_appBase = new WebAppBase();

+    var m_DataSourceUtils = new DataSourceUtils();

+    var m_webAppModel;

+    var m_viewModel;

+    var m_view;

+    var m_Binder;

+    var m_model;

+    var m_frameWork;

+

+    var cssfiles = [];

+

+    this.info = function() {

+        return {

+            defaultIcon: "WebApplications/CustomizableApp/Res/main_icon.png",

+            defaultName: "CustomizableApp"

+        };

+    };

+

+    this.load = function(webAppModel, params, framework)  {

+        m_frameWork = framework;

+        var jsfiles = [

+            "WebApplications/CustomizableApp/ViewModel.js",

+            "WebApplications/CustomizableApp/View.js",

+            "WebApplications/CustomizableApp/Model.js"

+        ];

+        var alwaysLoadableJsFiles = [];

+

+        function setupLoaded(ok, setup, setupName) {

+            if (ok) {

+                // load js and css files of main files, views and viewmodels, start the application

+                new MultipleDirectoryListTask(

+                    [

+                        "WebApplications/CustomizableApp/Views",

+                        "WebApplications/CustomizableApp/ViewModels",

+                        params.customization + "/ViewModels",

+                        params.customization + "/Views"

+                    ],

+                    m_webAppModel.getFileHandler()

+                ).taskOperation(function(ok, resources) {

+                    jsfiles = jsfiles.concat(resources.jsfiles);

+                    cssfiles = resources.cssfiles;

+                    //htmlfiles = resources.htmlfiles;

+                    m_appBase.load(jsfiles, alwaysLoadableJsFiles, start, m_webAppModel.getFileHandler());

+                });

+            } else {

+                alert("Failed to load setup " + setupName);

+            }

+        }

+

+        function appConfigLoaded(config) {

+            if (config.filesToInclude != undefined) {

+                alwaysLoadableJsFiles = config.filesToInclude;

+            }

+

+            if (params.setup != undefined) {

+                m_webAppModel.getSetupModel().loadSetup(params.setup, setupLoaded, false, params.setupParams);

+            } else if (config.setup != undefined) {

+                m_webAppModel.getSetupModel().loadSetup(config.setup, setupLoaded, false, config.setupParams);

+            } else {

+                alert('No setup was specified in config.');

+            }

+        }

+

+        m_webAppModel = webAppModel;

+        // set setup directory

+        if (params.customization != undefined) {

+            m_webAppModel.getSetupModel().setSetupDirectory(params.customization + '/Setups');

+        } else {

+            alert('Customizable app customization directory not set in params.');

+            return;

+        }

+

+        // load app config

+        m_webAppModel.loadAppConfig(params.customization + '/AppConfig.json', appConfigLoaded);

+    };

+

+    this.unload = function(webappUnloaded) {

+        m_appBase.unload(destroy);

+        webappUnloaded(true);

+    };

+

+    /** private functions */

+

+    function start(p_callback) {

+        m_model = new CCustomizableApp_Model(m_webAppModel, m_frameWork);

+        m_viewModel = new CViewModel(m_model, m_DataSourceUtils);

+        m_view = new CView(m_viewModel, "customAppMainview", "TSGuiFrameworkMain");

+

+        function callback(ok, msg) {

+            if (ok) {

+                m_webAppModel.getFileHandler().loadCssFiles(cssfiles, "customAppMainview");

+                m_viewModel.applicationCreated();

+                m_viewModel.initRequestSelectionsAndFiltersAtStart();

+                m_view.applicationCreated();

+                m_Binder = new CBinder(m_viewModel, m_view, m_DataSourceUtils);

+                m_Binder.start();

+            } else {

+                alert(msg);

+            }

+            if (typeof p_callback === "function") {

+                p_callback();

+            }

+        }

+

+        var taskList = new SyncTaskList([new GenericTask(m_viewModel.init), new GenericTask(m_view.init)], callback);

+

+        taskList.taskOperation();

+    }

+

+    function destroy() {

+        m_view.destroy();

+

+        m_Binder.stop();

+        m_Binder = undefined;

+

+        m_view = undefined;

+        m_viewModel = undefined;

+    }

+}

+

+function CBinder(aViewModel, aView, aDataSourceUtils)

+{

+    "use strict";

+

+    /** constructor and private members */

+    var mOutstandingRequests = 0;

+    var mLastResponse;

+    var mViewModel = aViewModel;

+    var mView = aView;

+    var ERunningState = {EStopped:0, ERunning:1, EStopping:2};

+    var mRunning = ERunningState.EStopped;

+    var mThis = this;

+    var mRefreshInterval = 1000;

+    if (mViewModel.getUIConfig().refreshInterval != undefined) {

+        mRefreshInterval = mViewModel.getUIConfig().refreshInterval;

+    }

+    var mDataSourceUtils = aDataSourceUtils;

+

+    aViewModel.setBinder(this);

+    var mInterval;

+

+    /** public functions */

+    this.start = function()

+    {

+        if (mRunning !== ERunningState.ERunning)

+        {

+            mRunning = ERunningState.ERunning;

+            mThis.mainLoop();

+            if (mRefreshInterval != -1) {

+                mInterval = setInterval(mThis.mainLoop, mRefreshInterval);

+            }

+        }

+    };

+

+    this.stop = function()

+    {

+        mRunning = ERunningState.EStopping;

+        if (mInterval != undefined)

+            clearInterval(mInterval);

+        mInterval = undefined;

+    };

+

+    this.notifyChange = function(aDisableViews, aFiredFromLoop)

+    {

+        function dataArrived(aData) {

+            if (aDisableViews && mViewModel.getUIConfig().overlayEnabledOnSelect) {

+                mView.enableViews();

+            }

+            responseArrived(aData)

+        }

+

+        if (mOutstandingRequests == 0 || !aFiredFromLoop)

+        {

+            if (aDisableViews && mViewModel.getUIConfig().overlayEnabledOnSelect) {

+                mView.disableViews();

+            }

+            mViewModel.getChangedData(dataArrived);

+            mOutstandingRequests++;

+        }

+    };

+

+    this.mainLoop = function()

+    {

+        if (mRunning === ERunningState.ERunning)

+        {

+            mThis.notifyChange(false, true);

+        }

+    };

+

+    this.reloadSetup = function()

+    {

+        mViewModel.getChangedData(function(aResponse) {

+            mView.destroySetupOnly();

+            mView.reInitSetup();

+            mViewModel.applicationCreated();

+            mView.applicationCreated();

+            mView.refreshView(true);

+            mLastResponse = null;

+            mThis.enableViews();

+            mThis.start();

+        });

+    }

+

+    this.enableViews = function() {

+        mView.enableViews();

+    };

+

+    this.disableViews = function(aDoNotShowSpinningCircle) {

+        mView.disableViews(aDoNotShowSpinningCircle);

+    };

+

+    this.isRunning = function() {

+        return mRunning === ERunningState.ERunning;

+    }

+

+    /** private functions */

+    function responseArrived(aData)

+    {

+        mOutstandingRequests--;

+        if (aData)

+        {

+            if (mRunning === ERunningState.ERunning)

+            {

+                if (!mDataSourceUtils.dataSkeletonEquals(mLastResponse, aData))

+                {

+                    if (mDataSourceUtils.isResponseToRequest(aData, mViewModel.getRequest()))

+                    {

+                        mLastResponse = aData;

+                        mViewModel.initRequestSelectionsAndFilters();

+                        mView.refreshView(true);

+                    }

+                }

+                else

+                {

+                    mView.refreshView(false);

+                }

+

+            }

+            else if (mRunning === ERunningState.EStopping)

+            {

+                mRunning = ERunningState.EStopped;

+            }

+        }

+    }

+}

+//# sourceURL=CustomizableApp\Main.js

diff --git a/htdocs/WebApplications/CustomizableApp/Model.js b/htdocs/WebApplications/CustomizableApp/Model.js
new file mode 100644
index 0000000..972c656
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/Model.js
@@ -0,0 +1,24 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CCustomizableApp_Model(p_webAppModel, p_applicationFramework) {

+    "use strict";

+

+    var m_webAppModel = p_webAppModel;

+    var m_DsRestApi = new DsRestAPI(m_webAppModel.getAppConfig().apiExtension);

+    var m_applicationFramework = p_applicationFramework;

+

+    this.getWebAppModel = function() {

+        return m_webAppModel;

+    };

+

+    this.getDsRestApi = function() {

+        return m_DsRestApi;

+    };

+

+    this.setAppParam = m_applicationFramework.setAppParam;

+

+    this.loadApp = m_applicationFramework.loadApp;

+}
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/Res/eventvector.png b/htdocs/WebApplications/CustomizableApp/Res/eventvector.png
new file mode 100644
index 0000000..96fcde4
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/Res/eventvector.png
Binary files differ
diff --git a/htdocs/WebApplications/CustomizableApp/Res/logo_animated.gif b/htdocs/WebApplications/CustomizableApp/Res/logo_animated.gif
new file mode 100644
index 0000000..3e54eaa
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/Res/logo_animated.gif
Binary files differ
diff --git a/htdocs/WebApplications/CustomizableApp/Res/main_icon.png b/htdocs/WebApplications/CustomizableApp/Res/main_icon.png
new file mode 100644
index 0000000..c1b74a8
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/Res/main_icon.png
Binary files differ
diff --git a/htdocs/WebApplications/CustomizableApp/View.css b/htdocs/WebApplications/CustomizableApp/View.css
new file mode 100644
index 0000000..508c24c
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/View.css
@@ -0,0 +1,46 @@
+.margin_logo {

+    display: inline-block;

+    vertical-align: middle;

+	margin-right: 5px;

+}

+

+.DsRestAPIStatisticsTable {

+    position: absolute;

+    left: 0px;

+    top: -25px;

+    z-index: 30;

+    font-size: 8px;

+}

+

+.DsRestAPIStatisticsTable tr td {

+    height: 10px;

+    font-weight: normal;

+    font-family: "Arial";

+    padding: 2px;

+}

+

+.CustomizableApp_LabelAtTop {

+    width: 100%;

+    font-weight: bold;

+}

+

+.NoData {

+    background: repeating-linear-gradient(144deg, #F1F1F1, #F1F1F1 5px, #E8E8E8 5px, #E8E8E8 10px);

+    background: -moz-repeating-linear-gradient(144deg, #F1F1F1, #F1F1F1 5px, #E8E8E8 5px, #E8E8E8 10px);

+}

+

+.waitingImage {

+	position: fixed;

+	top: calc(50% - 24px);

+	left: calc(50% - 24px);

+}

+

+#cll_DsRestAPI_error {

+    position: absolute;

+    left: calc(50% - 154px);

+    border: 2px solid red;

+    background-color: pink;

+    font-size: 20px;

+    top: -25px;

+    z-index: 10;

+}
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/View.html b/htdocs/WebApplications/CustomizableApp/View.html
new file mode 100644
index 0000000..edc1953
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/View.html
@@ -0,0 +1,27 @@
+<style id="WebAppStyle" type="text/css"></style>

+<style id="SetupStyle" type="text/css"></style>

+

+<div class="applications_header_class" style="position:relative;">

+    <table id="ajaxstats" class="DsRestAPIStatisticsTable">

+        <tbody>

+            <tr>

+                <td>Calls</td>

+                <td id="cll_DsRestAPI_FPS"></td>

+                <td>/sec ||| </td>

+                <td>Data Roundtrip</td>

+                <td id="cll_DsRestAPI_roundtrip"></td>

+                <td>ms ||| </td>

+                <!--<td>Server Time</td>

+                <td id="cll_DsRestAPI_serverTime"></td>-

+                <td>ms ||| </td>-->

+                <td>Data size</td>

+                <td id="cll_DsRestAPI_dataSize"></td>

+                <td>Byte</td>

+            </tr>

+        </tbody>

+    </table>

+    <p id="cll_DsRestAPI_error" class="hidden"></p>

+</div>

+

+<div id="id_setupTabs"></div>

+<div id="CustomAppSetup"></div>

diff --git a/htdocs/WebApplications/CustomizableApp/View.js b/htdocs/WebApplications/CustomizableApp/View.js
new file mode 100644
index 0000000..038b996
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/View.js
@@ -0,0 +1,183 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CView(a_viewModel, a_ID, a_parentID)

+{

+    "use strict";

+

+    /** private members and constructor */

+    var HTML = "WebApplications/CustomizableApp/View.html";

+    var CSS = "WebApplications/CustomizableApp/View.css";

+    var CSSNodeId = "WebAppStyle";

+    var CSSNodeIdSetup = "SetupStyle";

+    var CustomAppSetupID = "CustomAppSetup";

+    var m_parentDiv = document.getElementById(a_parentID);

+    var m_ID = a_ID;

+    var m_viewModel = a_viewModel;

+    var m_this = this;

+    var m_views = [];

+

+    /** public functions */

+    this.reInitSetup = function(a_callback)

+    {

+        $("#" + CSSNodeIdSetup).html(m_viewModel.getSetupStyle());

+        $("#" + CustomAppSetupID).html(m_viewModel.getSetupHtml());

+    }

+

+    this.init = function(a_callback)

+    {

+        var mainDiv = document.createElement("div");

+        mainDiv.setAttribute("id", m_ID);

+        m_parentDiv.appendChild(mainDiv);

+

+        function htmlLoaded(ok, data) {

+            if (ok) {

+                $("#" + m_ID).append(data);

+                a_viewModel.getFileHandler().loadCss(CSSNodeId, CSS);

+                m_this.reInitSetup();

+                a_callback(true);

+            } else {

+                a_callback(false, "Error loading " + HTML);

+            }

+        }

+

+        m_viewModel.loadFile(HTML, htmlLoaded);

+    };

+

+    this.destroy = function() {

+        $("#" + m_ID).remove();

+        $(window).off("resize", onWindowResize);

+    };

+

+    this.destroySetupOnly = function() {

+        $(".ui-tabs").tabs("option", "disabled", true);

+        $("#" + CustomAppSetupID).empty();

+        $("#" + CSSNodeIdSetup).empty();        

+        m_views = [];

+    };

+

+    this.applicationCreated = function()

+    {

+        m_views = [];

+        var viewDescriptors = m_viewModel.getViewDescriptors();

+        var viewCount = viewDescriptors.length;

+        var initedViewIDs = {}; /** stores inited info for parentIDs */

+        var idDependencyMap = {}; /** maps creatingIDs to parentIDs */

+        for (var i = 0; i < viewCount; ++i)

+        {

+            viewDescriptors[i].customData.parentID = viewDescriptors[i].parentID;

+            if (viewDescriptors[i].idsCreating)

+            {

+                viewDescriptors[i].customData.idsCreating = viewDescriptors[i].idsCreating;

+                for (var j = 0; j < viewDescriptors[i].customData.idsCreating.length; ++j)

+                    if (!idDependencyMap[viewDescriptors[i].customData.idsCreating[j]])

+                        idDependencyMap[viewDescriptors[i].customData.idsCreating[j]] = viewDescriptors[i].customData.parentID;

+                    else

+                        alert ("The same ID is created by multiple views. ID " + viewDescriptors[i].customData.idsCreating[j] + " is created by at least these 2 views: " + idDependencyMap[viewDescriptors[i].customData.idsCreating[j]] + " and " + viewDescriptors[i].customData.parentID);

+            }

+        }

+        //TODO: check if such a check is needed: alert ("Multiple views placed on the same ID. On ID " + viewDescriptors[i].customData.idsCreating[j] + " are placed more at least these 2 IDs: " + idDependencyMap[viewDescriptors[i].customData.idsCreating[j]] + " and " + viewDescriptors[i].customData.parentID);

+        var alertIndxs = [];

+        var lastNrOfInitedViews = 0;

+        while (Object.keys(initedViewIDs).length < viewCount)

+        {

+            var lastTryingID = "noID";

+            var lastTryingParentID = "noID";

+            for (var i = 0; i < viewCount; ++i)

+            {

+                if (window[viewDescriptors[i].class] && viewDescriptors[i].viewModelIndexes)

+                {

+                    /** if view is not inited yet AND (it has no parent dependency that needs to be created, OR it has dependency, but the dependency is already inited) */

+                    if (initedViewIDs[viewDescriptors[i].customData.parentID] != "inited" && (!idDependencyMap[viewDescriptors[i].customData.parentID] || initedViewIDs[idDependencyMap[viewDescriptors[i].customData.parentID]] == "inited"))

+                    {

+                        var lVMs = m_viewModel.getSubViewModels(viewDescriptors[i].viewModelIndexes);

+                        if (lVMs.length == 0)

+                          lVMs = [m_viewModel];

+                        

+                        var lId = "subView" + i;

+                        m_views[i] = new window[viewDescriptors[i].class](lVMs, lId, viewDescriptors[i].customData.parentID, viewDescriptors[i].customData);

+                        if (m_views[i].applicationCreated) {

+                            m_views[i].applicationCreated();

+                            ViewUtils.applyCss(viewDescriptors[i].customData, lId);

+                            ViewUtils.processCss(viewDescriptors[i].customData, viewDescriptors[i].customData.parentID);

+                        }

+                        initedViewIDs[viewDescriptors[i].customData.parentID] = "inited";

+                        if (!$("#" + viewDescriptors[i].customData.parentID).length)

+                        {

+                            if (alertIndxs[i] != "alertDisplayed")

+                            {

+                                alert ("No parent found for a view of class '"+viewDescriptors[i].class+"'. Missing object's ID is: " + viewDescriptors[i].customData.parentID);

+                                alertIndxs[i] = "alertDisplayed";

+                            }

+                        }

+                    }

+                    else

+                    {

+                        if (initedViewIDs[idDependencyMap[viewDescriptors[i].customData.parentID]] != "inited")

+                        {

+                            lastTryingID = viewDescriptors[i].customData.parentID;

+                            lastTryingParentID = idDependencyMap[viewDescriptors[i].customData.parentID];

+                        }

+                    }

+                }

+                else if (viewDescriptors[i].viewModelIndexes)

+                {

+                    alert("View class " + viewDescriptors[i].class + " does not exist!");

+                }

+            }

+            if (lastNrOfInitedViews < Object.keys(initedViewIDs).length)

+                lastNrOfInitedViews = Object.keys(initedViewIDs).length;

+            else

+            {

+                alert("Parent dependency error with the view with ID \" " + lastTryingID + "\". Its parent view with ID \"" + lastTryingParentID + "\" cannot be found.");

+                break;

+            }

+        }

+        

+        $(".ui-tabs").tabs("option", "disabled", false);

+        

+        $(window).on("resize", onWindowResize);

+        $("#" + CustomAppSetupID).height(ViewUtils.getSuggestedHeight(CustomAppSetupID));

+    };

+    

+    function onWindowResize(event) {

+        if (event.target == window) {

+            $("#" + CustomAppSetupID).height(ViewUtils.getSuggestedHeight(CustomAppSetupID));

+        }

+    }

+

+    this.refreshView = function(aFullRefresh)

+    {

+        /* aFullRefresh is True if the dataset's structure is changed. */

+        var viewCount = m_views.length;

+        for (var i = 0; i < viewCount; i++)

+            if (m_views[i] && m_views[i].refresh)

+                m_views[i].refresh(aFullRefresh);

+    };

+    

+    this.disableViews = function(aDoNotShowSpinningCircle) {

+        var opacity = m_viewModel.getUIConfig().overlayOpacity;

+        if (opacity == undefined) {

+            opacity = 0.0;

+        }

+        if ($(".ui-widget-overlay")[0] == undefined) {

+            var html;

+            if (aDoNotShowSpinningCircle) {

+                html = '<div class="ui-widget-overlay ui-front" style="z-index: 1000; opacity: ' + opacity + ';"></div>';

+            } else {

+                html = '<div class="ui-widget-overlay ui-front" style="z-index: 1000; opacity: ' + opacity + ';"></div><img src="WebApplicationFramework/Res/waiting.gif" class="waitingImage">';

+            }

+            $(m_parentDiv).append(html);

+        }

+    };

+    

+    this.enableViews = function() {

+        $(".ui-widget-overlay").remove();

+        $(".waitingImage").remove();

+    };

+

+    /** private functions */

+}

+//# sourceURL=CustomizableApp\Views\View.js

diff --git a/htdocs/WebApplications/CustomizableApp/ViewModel.js b/htdocs/WebApplications/CustomizableApp/ViewModel.js
new file mode 100644
index 0000000..eec5f69
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModel.js
@@ -0,0 +1,508 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+/** App specific runtime behaviour */
+function CViewModel(aModel, aDataSourceUtils)
+{
+    "use strict";
+
+    /** private members */
+    var mDataSourceUtils = aDataSourceUtils;
+    var mWebAppModel = aModel.getWebAppModel();
+    var mFileHandler = mWebAppModel.getFileHandler();
+    var mDsRestAPI = aModel.getDsRestApi();
+    var mUIConfig = mWebAppModel.getAppConfig();
+    var mViewIsDisabledBecauseConnectionWasInterrupted = false;
+    var mBinder;
+    var mRequest = [];
+    var mViewModels = [];
+    var mSetupList;
+    var mResponse;
+    var mModel = aModel;
+    var mThis = this;
+
+    var mSelectionToChangeToValue = [];
+
+    this.getSetupModel = mWebAppModel.getSetupModel;
+    this.getSetupList = function() {
+        if (mSetupList == undefined) {
+            alert("callback for mSetupList should be called sooner");
+            return [];
+        }
+        return mSetupList;
+    };
+
+    this.initRequestSelectionsAndFiltersAtStart = function() {
+        mSelectionToChangeToValue = [];
+        triggerSelectionChangeAtStart(mRequest, []);
+        loadRangeFilters(mRequest, []);
+    };
+
+    this.initRequestSelectionsAndFilters = function()
+    {
+        if (mSelectionToChangeToValue.length != 0) {
+            for (var i = 0; i < mSelectionToChangeToValue.length; ++i) {
+                var request = mThis.getRequestFromPath(mSelectionToChangeToValue[i]);
+                var response = mThis.getResponseElement(mSelectionToChangeToValue[i]);
+                if (response != undefined && response.list != undefined && response.list[0] != undefined && response.list[0].node != undefined) {
+                    request.getData.selectionValues = [response.list[0].node.val];
+                    request.getData.selection = [0];
+                    var value = {
+                        "selection": request.getData.selection,
+                        "selectionValues": request.getData.selectionValues
+                    };
+                    sessionStorage.setItem(getRequestKey(mSelectionToChangeToValue[i], "selection"), JSON.stringify(value));
+                    sessionStorage.setItem(getRequestKeyAlternative(mSelectionToChangeToValue[i], "selection"), JSON.stringify(value));
+                }
+            }
+            mSelectionToChangeToValue = [];
+        }
+    };
+
+    this.getRequest = function()
+    {
+        return mRequest;
+    };
+
+    this.getDsRestAPI = function()
+    {
+        return mDsRestAPI;
+    };
+
+    this.getFileHandler = function() {
+        return mFileHandler;
+    }
+
+    this.init = function(p_callback) {
+        function setupsLoaded(setups) {
+            mSetupList = setups;
+            p_callback(true);
+        }
+
+        sessionStorage.clear();
+        mWebAppModel.getSetupModel().listSetups(setupsLoaded);
+        //p_callback(true);
+    };
+
+    function getSelectionObject(aRequest, aPath)
+    {
+        var lRq = mRequest[aPath[0]].getData;
+        for (var i = 1; i < aPath.length; ++i)
+        {
+            lRq = lRq.children[aPath[i]].getData;
+        }
+        return lRq;
+    }
+
+    this.applicationCreated = function()
+    {
+        mRequest = [];
+        mViewModels = [];
+        mRequest = mWebAppModel.getSetupModel().getSetup().request.getData();
+        var viewModelDescriptors = mWebAppModel.getSetupModel().getSetup().viewmodels.getData();
+        var viewModelCount = viewModelDescriptors.length;
+        for (var i = 0; i < viewModelCount; ++i)
+        {
+            if (window[viewModelDescriptors[i].class])
+            {
+                mViewModels[i] = new window[viewModelDescriptors[i].class](this, viewModelDescriptors[i].customData);
+                mViewModels[i].loadFile = mThis.loadFile;
+                mViewModels[i].getDataList = mDsRestAPI.getList;
+                for (var j = 0; j < viewModelDescriptors[i].dataPathList.length; ++j)
+                    mViewModels[i].setReponseDataPath(j, viewModelDescriptors[i].dataPathList[j]);
+                if (viewModelDescriptors[i].selectionToControlPathList && mViewModels[i].setSelectionToControl)
+                {
+                    for (var j = 0; j < viewModelDescriptors[i].selectionToControlPathList.length; ++j)
+                        mViewModels[i].setSelectionToControl(getSelectionObject(mRequest, viewModelDescriptors[i].selectionToControlPathList[j]));
+                }
+            }
+            else
+            {
+                alert("Viewmodel class " + viewModelDescriptors[i].class + " does not exist!");
+            }
+        }
+        for (var i = 0; i < mViewModels.length; ++i)
+            mViewModels[i].setBinder(mBinder);
+    };
+
+    this.getViewDescriptors = function()
+    {
+        return mWebAppModel.getSetupModel().getSetup().views.getData();
+    };
+
+    this.getSetupStyle = function()
+    {
+        return mWebAppModel.getSetupModel().getSetup().css.getData();
+    };
+
+    this.getSetupHtml = function()
+    {
+        return mWebAppModel.getSetupModel().getSetup().html.getData();
+    };
+
+    this.getResponseElement = function(aReponseDataPath, aLastSelectionIndexes)
+    {
+        if (aLastSelectionIndexes == undefined)
+            aLastSelectionIndexes = [];
+
+        var lNextSelectionIndex = 0;
+
+        var lElement = undefined;
+        if (aReponseDataPath && mResponse)
+        {
+            lElement = mResponse[aReponseDataPath[0]];
+            if (lElement)
+            {
+                var lRq = mRequest[aReponseDataPath[0]];
+                for (var i = 1; i < aReponseDataPath.length; ++i)
+                {
+                    if (lElement && lElement.list && lRq.getData.selection && lRq.getData.selection.length > 0)
+                    {
+                        if (lRq.getData.selectionValues && lRq.getData.selectionValues.length > 0 && lElement.list[0] && lElement.list[0].node.childVals) {
+                            lElement = lElement.list[0].node.childVals[aReponseDataPath[i]];
+                        } else if (lElement.list[lRq.getData.selection[0]] && lElement.list[lRq.getData.selection[0]].node.childVals) {
+                            lElement = lElement.list[lRq.getData.selection[0]].node.childVals[aReponseDataPath[i]];
+                        } else {
+                            lElement = undefined;
+                            break;
+                        }
+                    }
+                    else if (lElement && lElement.list && aLastSelectionIndexes[lNextSelectionIndex] != undefined) {
+                        lElement = lElement.list[aLastSelectionIndexes[lNextSelectionIndex]].node.childVals[aReponseDataPath[i]];
+                        ++lNextSelectionIndex;
+                    }
+                    else if (lElement && lElement.node)
+                    {
+                        if (lElement.node.childVals)
+                            lElement = lElement.node.childVals[aReponseDataPath[i]];
+                        else {
+                            lElement = undefined;
+                            break;
+                        }
+                    }
+                    else
+                        lElement = {"error": "cannot determine node"};
+                    if (lRq.getData.children)
+                        lRq = lRq.getData.children[aReponseDataPath[i]];
+                }
+            }
+        }
+        else
+            lElement = mResponse;
+        return lElement;
+    };
+
+    this.setResponseElement = function(aReponseDataPath, aValue, aIndexInList, aLastSelectionIndexes, aCallback, aAdditionalData)
+    {
+        function dataSet(response) {
+            if (mUIConfig.overlayEnabledOnSetData)
+                mBinder.enableViews();
+            if (aCallback != undefined)
+                aCallback(response);
+            mBinder.notifyChange();
+        }
+
+        if (aAdditionalData == undefined) {
+            aValue = "" + aValue;
+            var setData = mDataSourceUtils.setValue(mRequest, mResponse, aReponseDataPath, aIndexInList, aValue, aLastSelectionIndexes);
+            if (setData != undefined) {
+                if (mUIConfig.overlayEnabledOnSetData) {
+                    mBinder.disableViews();
+                }
+                mDsRestAPI.getList([setData], dataSet);
+            }
+        } else if (aAdditionalData.setAppParams != undefined) {
+            for (var i = 0; i < aAdditionalData.setAppParams.params.length; ++i) {
+                var param = aAdditionalData.setAppParams.params[i];
+                mModel.setAppParam(aAdditionalData.setAppParams.appName, param.key, param.value);
+            }
+        } else if (aAdditionalData.loadApp != undefined) {
+            mModel.loadApp(aAdditionalData.loadApp);
+        }
+    };
+
+    this.select = function(aSelectionObject, aValue) {
+        saveRangeFilters(mRequest, []);
+
+        aSelectionObject.selectionValues = undefined;
+        if (aSelectionObject.selection)
+            aSelectionObject.selection[0] = aValue;
+        else
+            aSelectionObject.selection = [aValue];
+
+        updateSelectionsFromStorage(aSelectionObject);
+        loadRangeFilters(mRequest, []);
+    };
+
+    this.selectByValue = function(aSelectionObject, aValue, aIndex) {
+        saveRangeFilters(mRequest, []);
+
+        if (aSelectionObject.selectionValues)
+            aSelectionObject.selectionValues[0] = aValue;
+        else
+            aSelectionObject.selectionValues = [aValue];
+
+        if (aSelectionObject.selection)
+            aSelectionObject.selection[0] = aIndex;
+        else
+            aSelectionObject.selection = [aIndex];
+
+        updateSelectionsFromStorage(aSelectionObject);
+        loadRangeFilters(mRequest, []);
+    };
+
+    this.getSubViewModels = function(aIndexes)
+    {
+        var lViewmodels = [];
+        for (var i = 0; i < aIndexes.length; ++i) {
+            lViewmodels.push(mViewModels[aIndexes[i]]);
+        }
+        return lViewmodels;
+    };
+
+    this.setBinder = function(aBinder)
+    {
+        mBinder = aBinder;
+        for (var i = 0; i < mViewModels.length; ++i)
+            mViewModels[i].setBinder(mBinder);
+    };
+
+    this.getChangedData = function(aHandler)
+    {
+        function saveResponse(aResponse) {
+            if (aResponse != undefined && aResponse.length > 0) {
+                if (aResponse[0].node == undefined || aResponse[0].node.val != "No answer") {
+                    if (mViewIsDisabledBecauseConnectionWasInterrupted) {
+                        mViewIsDisabledBecauseConnectionWasInterrupted = false;
+                        mBinder.enableViews();
+                    }
+                    mResponse = aResponse;
+                } else {
+                    mViewIsDisabledBecauseConnectionWasInterrupted = true;
+                    mBinder.disableViews();
+                }
+            }
+            aHandler(aResponse);
+        }
+        mDsRestAPI.getList(mRequest, saveResponse);
+    };
+
+    this.getUIConfig = function() {
+        return mUIConfig;
+    };
+
+    this.loadFile = function(url, callback) {
+        return mFileHandler.loadFile(url, callback);
+    };
+
+    this.loadSetup = function(a_setup, a_setupParams, a_doNotShowSpinningCircle) {
+        if (mSetupList == undefined) {
+            alert("callback for mSetupList should be called sooner");
+            return;
+        }
+
+        function setupLoaded(ok, setup, setupLocation) {
+            mResponse = undefined;
+            mRequest = mWebAppModel.getSetupModel().getSetup().request.getData();
+            mThis.initRequestSelectionsAndFiltersAtStart();
+            mBinder.reloadSetup();
+        }
+        var setupExists = false;
+        for (var i = 0; i < mSetupList.length; ++i)
+            if (mSetupList[i] == a_setup)
+                setupExists = true;
+        if (setupExists)
+        {
+            saveRangeFilters(mRequest, []);
+            mBinder.disableViews(a_doNotShowSpinningCircle);
+            if (mBinder.isRunning()) {
+                mBinder.stop();
+                mWebAppModel.getSetupModel().loadSetup(a_setup, setupLoaded, false, a_setupParams);
+            }
+        }
+        else
+            alert("No such setup to load: " + a_setup);
+    };
+
+    this.isRunning = function() {
+        return mBinder.isRunning();
+    };
+
+    // ------------------------------------------------------------------------------------------------
+
+    this.getRequestFromPath = function(aReponseDataPaths)
+    {
+        var lRequest = null;
+        if (aReponseDataPaths)
+        {
+            lRequest = mRequest[aReponseDataPaths[0]];
+            for (var i = 1; i < aReponseDataPaths.length; ++i)
+                lRequest =  lRequest.getData.children[aReponseDataPaths[i]];
+        }
+        else
+            lRequest = mRequest;
+        return lRequest;
+    };
+
+    function updateSelectionsFromStorage(p_request) {
+        var requestPath = [];
+        getRequestPath(p_request, mRequest, requestPath);
+
+        var value = {
+            "selection": p_request.selection,
+            "selectionValues": p_request.selectionValues
+        };
+        sessionStorage.setItem(getRequestKey(requestPath, "selection"), JSON.stringify(value));
+        sessionStorage.setItem(getRequestKeyAlternative(requestPath, "selection"), JSON.stringify(value));
+
+        setSelections(requestPath, mThis.getRequestFromPath(requestPath).getData.children);
+    }
+
+    function getRequestPath(p_request, p_list, p_path) {
+        for (var i = 0; i < p_list.length; ++i) {
+            p_path.push(i);
+
+            if (p_request == p_list[i].getData) {
+                return true;
+            }
+
+            if (p_list[i].getData.children != undefined && getRequestPath(p_request, p_list[i].getData.children, p_path)) {
+                return true;
+            }
+
+            p_path.pop(i);
+        }
+    }
+
+    function getRequestKey(p_path, p_type) {
+        var key = '';
+        var currentPath = [];
+        for (var i = 0; i < p_path.length - 1; ++i) {
+            currentPath.push(p_path[i]);
+            var request = mThis.getRequestFromPath(currentPath);
+            if (request.getData.selectionValues != undefined) {
+                key += request.getData.selectionValues + "_";
+            } else if (request.getData.selection != undefined) {
+                var response = mThis.getResponseElement(currentPath);
+                if (response != undefined && response.list != undefined && response.list[request.getData.selection[0]] != undefined && response.list[request.getData.selection[0]].node != undefined) {
+                    key += response.list[request.getData.selection[0]].node.val + "_";
+                } else {
+                    return getRequestKeyAlternative(p_path, p_type);
+                }
+            }
+        }
+
+        key += JSON.stringify(p_path);
+        key = mWebAppModel.getSetupModel().getSetup().name + "_" + p_type + "_" + key;
+
+        return key;
+    }
+
+    function getRequestKeyAlternative(p_path, p_type) {
+        var key = '';
+        var currentPath = [];
+        for (var i = 0; i < p_path.length - 1; ++i) {
+            currentPath.push(p_path[i]);
+            var request = mThis.getRequestFromPath(currentPath);
+            if (request.getData.selection != undefined) {
+                key += request.getData.selection[0] + "_";
+            }
+        }
+
+        key += JSON.stringify(p_path);
+        key = mWebAppModel.getSetupModel().getSetup().name + "_" + p_type + "_" + key;
+
+        return key;
+    }
+
+    function setSelections(p_path, p_list) {
+        if (p_list != undefined) {
+            for (var i = 0; i < p_list.length; ++i) {
+                p_path.push(i);
+
+                if (p_list[i].getData.selection != undefined || p_list[i].getData.selectionValues != undefined) {
+                    var key = getRequestKey(p_path, "selection");
+                    var value = sessionStorage.getItem(key);
+                    if (value != undefined) {
+                        value = JSON.parse(value);
+                        p_list[i].getData.selection = value.selection;
+                        p_list[i].getData.selectionValues = value.selectionValues;
+                    } else {
+                        p_list[i].getData.selectionValues = undefined;
+                        p_list[i].getData.selection = [0];
+                        mSelectionToChangeToValue.push(mcopy(p_path));
+                    }
+                }
+
+                setSelections(p_path, p_list[i].getData.children);
+
+                p_path.pop(i);
+            }
+        }
+    }
+
+    function triggerSelectionChangeAtStart(a_requests, a_path) {
+        for (var i = 0; i < a_requests.length; ++i) {
+            a_path.push(i);
+
+            if (a_requests[i].getData.selection != undefined && a_requests[i].getData.selection.length > 0) {
+                var response = mThis.getResponseElement(a_path);
+
+                var key = getRequestKey(a_path, "selection");
+                var value = sessionStorage.getItem(key);
+                if (value != undefined) {
+                    value = JSON.parse(value);
+                    a_requests[i].getData.selectionValues = value.selectionValues;
+                    a_requests[i].getData.selection = value.selection;
+                } else {
+                    mSelectionToChangeToValue.push(mcopy(a_path));
+                }
+            }
+            if (a_requests[i].getData.children != undefined) {
+                triggerSelectionChangeAtStart(a_requests[i].getData.children, a_path);
+            }
+
+            a_path.pop(i);
+        }
+    }
+
+    function saveRangeFilters(p_requests, p_path) {
+        for (var i = 0; i < p_requests.length; ++i) {
+            p_path.push(i);
+
+            if (p_requests[i].getData.rangeFilter != undefined) {
+                sessionStorage.setItem(getRequestKey(p_path, "rangeFilter"), JSON.stringify(p_requests[i].getData.rangeFilter));
+                sessionStorage.setItem(getRequestKeyAlternative(p_path, "rangeFilter"), JSON.stringify(p_requests[i].getData.rangeFilter));
+            }
+
+            if (p_requests[i].getData.children != undefined) {
+                saveRangeFilters(p_requests[i].getData.children, p_path);
+            }
+            p_path.pop(i);
+        }
+    }
+
+    function loadRangeFilters(p_requests, p_path) {
+        for (var i = 0; i < p_requests.length; ++i) {
+            p_path.push(i);
+
+            if (p_requests[i].getData.rangeFilter != undefined) {
+                var key = getRequestKey(p_path, "rangeFilter");
+                var rangeFilter = sessionStorage.getItem(key);
+                if (rangeFilter != undefined) {
+                    p_requests[i].getData.rangeFilter = JSON.parse(rangeFilter);
+                } else {
+                    p_requests[i].getData.rangeFilter.offset = 0;
+                }
+            }
+
+            if (p_requests[i].getData.children != undefined) {
+                loadRangeFilters(p_requests[i].getData.children, p_path);
+            }
+            p_path.pop(i);
+        }
+    }
+}
+//# sourceURL=CustomizableApp\ViewModel.js
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_2dIteratorSelector.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_2dIteratorSelector.js
new file mode 100644
index 0000000..7ef69d8
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_2dIteratorSelector.js
@@ -0,0 +1,118 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_2dIteratorSelector(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    v_options.iteratorColumnPosition = -1;
+    var base = new CViewModel_DynamicTable(p_viewmodel, v_options);
+    
+    var v_rowIndexes = [0];
+    var v_tableData = {
+        "table": []
+    };
+    
+    var v_selections = [];
+    var v_binder;
+    
+    /** public functions - interface for parent */ 
+
+    this.setSelectionToControl = function(p_selection) {
+        v_selections.push(p_selection);
+    };
+    this.setReponseDataPath = base.setReponseDataPath;
+    this.setBinder = function(p_binder) {
+        v_binder = p_binder;
+    };
+    
+	/** public functions - interface for views */
+    
+    this.select = function(p_index) {
+        var select1 = 0;
+        var select2 = 0;
+        for (var i = v_rowIndexes.length - 1; i >= 0; --i) {
+            if (p_index >= v_rowIndexes[i]) {
+                select1 = i;
+                select2 = p_index - v_rowIndexes[i];
+                break;
+            }
+        }
+        
+        v_viewmodel.select(v_selections[0], select1);
+        for (var i = 1; i < v_selections.length; ++i) {
+            v_viewmodel.select(v_selections[i], select2);
+        }
+        
+        v_binder.notifyChange(true);
+    };
+    
+    this.getList = function() {
+        v_tableData = base.getTable();
+        var list = flattenTable();
+        return list;
+    };
+    
+    /** private Classes */
+    
+    function flattenTable() {
+        v_rowIndexes = [];
+        var list = {
+            "values" : [[]],
+            "selections": [[]]
+        };
+        var elements = 0;
+        for (var i = 0; i < v_tableData.table.length; ++i) {
+            v_rowIndexes.push(elements);
+            for (var j = 0; j < v_tableData.table[i].length; ++j) {
+                if (v_options.text != undefined) {
+                    list.values[0].push([getValue(v_tableData.table[i][j].val, i, j, v_options.text)]);
+                } else {
+                    list.values[0].push([v_tableData.table[i][j].val]);
+                }
+                
+                if (v_selections[0].selection[0] == i && v_selections[1].selection[0] == j) {
+                    list.selections[0][0] = elements;
+                }
+                ++elements;
+            }
+        }
+        return list;
+    }
+    
+    function getValue(val, row, col, text) {
+        text = text.replace(/#i/gi, row);
+        text = text.replace(/#j/gi, col);
+        text = text.replace(/#val/gi, val);
+        return text;
+    }
+}
+
+CViewModel_2dIteratorSelector.getHelp = function() {
+    return "Viewmodel that can be used to set the selection of two iterators.";
+};
+
+CViewModel_2dIteratorSelector.providesInterface = function() {
+    return ["getList", "select"];
+};
+
+CViewModel_2dIteratorSelector.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_2dIteratorSelector",
+        "type": "object",
+        "properties": {
+            "text": {
+                "type": "string",
+                "description": "Display additional data, use #i for the rows, #j for the columns, and #val for the value. If not defined, the value will be used."
+            }
+        }
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\CViewModel_2dIteratorSelector.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_AutoGUI.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_AutoGUI.js
new file mode 100644
index 0000000..85872be
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_AutoGUI.js
@@ -0,0 +1,96 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_AutoGUI(aViewModel, aOptions)

+{

+    "use strict";

+    /** private members */

+    var mViewModel;

+    var mBinder;

+    var mReponseDataPaths;

+

+    /** constructor */

+    mViewModel = aViewModel;

+    mReponseDataPaths = [];

+

+    /** public functions - Interface for parent */ 

+    this.setSelectionToControl = function(aSelection)

+    {};

+    

+    this.setReponseDataPath = function(aExpectedReponseDataIndex, aReponseDataPath)

+    {

+        mReponseDataPaths[aExpectedReponseDataIndex] = aReponseDataPath;

+    };

+    

+    this.setBinder = function(aBinder)

+    {

+        mBinder = aBinder;

+    };

+

+	/** public functions - Interface for views */ 

+    this.getResponseElement = function()

+    {

+        return mViewModel.getResponseElement(mReponseDataPaths[0]);

+    };

+    

+    this.command = function(aCklickedExpandedGetData, aOrigGetData, aValue, aIsContainer, aIsText)

+    {

+        function dataHasBeenSet(aData)

+        {

+            mBinder.notifyChange();

+        }

+        if (aCklickedExpandedGetData !== undefined && aOrigGetData.children !== undefined)

+        {

+            if (aOrigGetData.selection !== undefined)

+            {

+                if (aIsContainer)

+                    aOrigGetData.selection = undefined;

+                else if (aOrigGetData.selection[0] === aCklickedExpandedGetData.idxInList)

+                    aOrigGetData.selection = [];

+                else if (aCklickedExpandedGetData.idxInList != null)

+                    aOrigGetData.selection = [aCklickedExpandedGetData.idxInList];

+            }

+            else

+            {

+                if (aIsContainer)

+                    aOrigGetData.selection = [];

+                else if (aCklickedExpandedGetData.idxInList != null)

+                    aOrigGetData.selection = [aCklickedExpandedGetData.idxInList];

+            }

+            mBinder.notifyChange("Autogui changes");

+        }

+        else if (aCklickedExpandedGetData !== undefined && aOrigGetData.children === undefined && aIsText)

+        {

+            var newVal = prompt("Please enter new value", aValue);

+            if (newVal != null)

+            {

+                var lIndxList = [];

+                if (aCklickedExpandedGetData.idxInList !== undefined)

+                    lIndxList[0] = aCklickedExpandedGetData.idxInList;

+                mViewModel.getDsRestAPI().setData(dataHasBeenSet, aCklickedExpandedGetData.source, aCklickedExpandedGetData.element, newVal, aCklickedExpandedGetData.tp, aCklickedExpandedGetData.params, aCklickedExpandedGetData.ptcname, lIndxList);

+            }

+        }

+    };

+}

+

+CViewModel_AutoGUI.getHelp = function() {

+    return "This viewmodel is used with the same named view to visualize the response tree.";

+}

+

+CViewModel_AutoGUI.providesInterface = function() {

+    return ["getResponseElement", "command"];

+};

+

+CViewModel_AutoGUI.getCustomDataSchema = function() {

+    return {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "title": "Custom data for CViewModel_AutoGUI",

+        "type": "object",

+        "properties": {},

+        "additionalProperties": false

+    };

+};

+

+//# sourceURL=CustomizableApp\ViewModels\ViewModel_AutoGUI.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Chart.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Chart.js
new file mode 100644
index 0000000..30d6c67
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Chart.js
@@ -0,0 +1,198 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_Chart(p_viewmodel, p_options) {

+    "use strict";

+

+    /** constructor */

+    

+    var v_viewmodel = p_viewmodel;

+    var v_options = p_options;

+    

+    var v_dataPaths = [];

+    var v_visible = [];

+        

+    /** public functions - interface for parent */

+    

+    this.setSelectionToControl = function(p_selection) {};

+    this.setBinder = function(p_binder) {};

+    this.setReponseDataPath = function(p_index, p_path) {

+        v_dataPaths[p_index] = p_path;

+    };

+	

+    /** public functions - interface for views */

+    

+    this.getChartData = function() {

+        return getDatasetsAndNavigationData();

+    };

+    

+    this.toggleSeries = function(index) {

+        if (v_visible[index] == undefined) {

+            v_visible[index] = false;

+        } else {

+            v_visible[index] = !v_visible[index];

+        }

+    };

+    

+    this.isSeriesVisible = function(index) {

+        return v_visible[index] == undefined || v_visible[index] == true;

+    }

+    

+    /** private functions */

+    

+    function getTimelineContent(tp, stringContent) {

+        if (tp == 1) {

+            return parseInt(stringContent);

+        } else if (tp == 2) {

+            return parseFloat(stringContent);

+        } else if (tp == 3) {

+            return stringContent == "true";

+        } else {

+            return stringContent

+        }

+    }

+    

+    function addTimelineData(data, timeline) {

+        try {

+            timeline = JSON.parse(timeline);

+            if (timeline.x.length != timeline.y.length) {

+                return false

+            } else {

+                for (var i = 0; i < timeline.x.length; ++i) {

+                    data.push([timeline.x[i] * 1000, getTimelineContent(timeline.tp, timeline.y[i])]);

+                }

+                return true;

+            }

+        } catch (e) {

+            return false;

+        }

+    }

+    

+    function getDatasetsAndNavigationData() {

+        var navigationData = {x: {pan: {min: -1, max: 1}, zoom: {min: 1, max: null}}, y: {pan: {min: -1, max: 1}, zoom: {min: 1, max: null}}};

+        var dataSets = [];

+        

+        var counter = 0;

+        for (var i = 0; i < v_dataPaths.length; ++i) {

+            var response = v_viewmodel.getResponseElement(v_dataPaths[i]);

+            if (response != undefined) {

+                var request = v_viewmodel.getRequestFromPath(v_dataPaths[i]);

+                if (request.getData.timeline != undefined && response.node != undefined) {

+                    var dataSet = getEmptyDataSet(counter, request != undefined ? request.getData.element : "Series" + counter);

+                    if (addTimelineData(dataSet.data, response.node.val)) {

+                        dataSets.push(dataSet);

+                        ++counter;

+                    }

+                } else if (response != undefined && response.list != undefined && request.getData.children != undefined) {

+                    for (var j = 0; j < request.getData.children.length; ++j) {

+                        if (request.getData.children[j].getData.timeline != undefined) {

+                            for (var k = 0; k < response.list.length; ++k) {

+                                if (response.list[k].node.childVals != undefined && response.list[k].node.childVals[j] != undefined) {

+                                    var childResponse = response.list[k].node.childVals[j];

+                                    var dataSet = getEmptyDataSet(counter, response.list[k].node.val);

+                                    if (addTimelineData(dataSet.data, childResponse.node.val)) {

+                                        dataSets.push(dataSet);

+                                        ++counter;

+                                    }

+                                }

+                            }

+                        }

+                    }

+                }

+            }

+        }

+        

+        if (dataSets.length != 0 && dataSets[0].data[0] != undefined) {

+            navigationData.x.pan.min = dataSets[0].data[0][0] + 1;

+            navigationData.y.pan.min = dataSets[0].data[0][1] + 1;

+        }

+        

+        for (var i = 0; i < dataSets.length; ++i) {

+            for (var j = 0; j < dataSets[i].data.length; ++j) {

+                navigationData.x.pan.max = Math.max(navigationData.x.pan.max, dataSets[i].data[j][0] + 1);

+                navigationData.x.pan.min = Math.min(navigationData.x.pan.min, dataSets[i].data[j][0] - 1);

+                navigationData.y.pan.max = Math.max(navigationData.y.pan.max, dataSets[i].data[j][1] + 1);

+                navigationData.y.pan.min = Math.min(navigationData.y.pan.min, dataSets[i].data[j][1] - 1);

+            }

+        }

+        

+        return {

+            "dataSets": dataSets,

+            "navigationRanges": navigationData

+        }

+    }

+    

+    function getEmptyDataSet(counter, altLabel) {

+        var data;

+        if (v_options.dataSet == undefined || v_options.dataSet[counter] == undefined) {

+            data = {

+                "label": altLabel,

+                "data": [],

+                "lines": {

+                    "show": v_visible[counter] == undefined || v_visible[counter] == true

+                }

+            }

+        } else {

+            data = {

+                "label": v_options.dataSet[counter].label,

+                "data": [],

+                "color": v_options.dataSet[counter].color,

+                "highlightColor": v_options.dataSet[counter].highlightColor,

+                "lines": {

+                    "show": v_visible[counter] == undefined || v_visible[counter] == true

+                }

+            }

+        }

+        

+        return data;

+    }

+    

+}

+

+CViewModel_Chart.getHelp = function() {

+    return "The viewmodel creates the data for a timeseries chart.";

+};

+

+CViewModel_Chart.providesInterface = function() {

+    return ["getChartData", "toggleSeries", "isSeriesVisible"];

+};

+

+CViewModel_Chart.getCustomDataSchema = function() {

+    return {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "title": "Custom data for CViewModel_Chart",

+        "type": "object",

+        "properties": {

+            "dataSet": {

+                "type": "array",

+                "format": "tabs",

+                "items": {

+                    "type": "object",

+                    "properties": {

+                        "label": {

+                            "type": "string",

+                            "description": "If present, it will be used as the label of the data."

+                        },

+                        "color": {

+                            "type": "string",

+                            "description": "If present, it will be used as the color of the data.",

+                            "pattern": "^#(?:[0-9a-fA-F]{3}){1,2}$"

+                        },

+                        "highlightColor": {

+                            "type": "string",

+                            "description": "If present, it will be used as the highlight color of the data.",

+                            "pattern": "^#(?:[0-9a-fA-F]{3}){1,2}$"

+                        }

+                    },

+                    "additionalProperties": false,

+                    "required": ["label"]

+                }

+            }

+        },

+        "additionalProperties": false

+    };

+};

+

+//# sourceURL=CustomizableApp\ViewModels\ViewModel_Chart.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Clients.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Clients.js
new file mode 100644
index 0000000..7663b75
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Clients.js
@@ -0,0 +1,242 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_Clients(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var v_options = p_options;
+    var base = new CViewModel_TableForLargeData(p_viewmodel, p_options);
+    
+    var v_flexAligner = new CViewModel_FlexAligner();
+    
+    var v_tableData = {
+        "table": []
+    };
+    var v_header = [];
+    var v_viewmodels = [];
+    var v_firstSeparatorExists;
+    
+    /** public functions - interface for parent */ 
+
+    this.setSelectionToControl = base.setSelectionToControl;
+    this.setReponseDataPath = base.setReponseDataPath;
+    this.setBinder = base.setBinder;
+	
+	/** public functions - interface for views */ 
+
+    this.getViewmodelBundle = function() {
+        var newTableData = base.getTable();
+        var newHeader = base.getHeader();
+        
+        // in the check we use both v_tableData and newTableData
+        var fullRefresh = checkIfFullRefreshNeeded(newTableData);
+        v_tableData = newTableData;
+        v_header = newHeader;
+        updateViewmodels();
+        
+        return {
+            "viewmodels": v_viewmodels,
+            "fullRefresh": fullRefresh,
+            "firstSeparatorExists": v_firstSeparatorExists
+        };
+    };
+    
+    this.getRange = base.getRange;
+    this.getPosition = base.getPosition;
+    this.setPosition = base.setPosition;
+    this.getViewportSize = base.getViewportSize;
+    this.isStreaming = base.isStreaming;
+
+    /** private functions */
+    
+    function checkIfFullRefreshNeeded(newTableData) {
+        if ((newTableData.separators == undefined && v_tableData.separators == undefined) || 
+            (newTableData.separators != undefined && v_tableData.separators != undefined && newTableData.separators.length == v_tableData.separators.length)) {
+            
+            if (newTableData.separators != undefined && v_tableData.separators != undefined) {
+                var columnIndexThatContainsTheSize = v_options.numberOfElementsInFirstAligner + v_options.numberOfElementsInSecondAligner;
+                var limitForFirstSeparatorExistance;
+                if (newTableData.separators.length > 1) {
+                    limitForFirstSeparatorExistance = newTableData.separators[1].index;
+                } else {
+                    limitForFirstSeparatorExistance = newTableData.table.length;
+                }
+                var firstSeparatorExists = true;
+                if (base.getPosition() != 0) {
+                    for (var i = 0; i < limitForFirstSeparatorExistance; ++i) {
+                        if (parseInt(newTableData.table[i][columnIndexThatContainsTheSize].val) != limitForFirstSeparatorExistance) {
+                            firstSeparatorExists = false;
+                            break;
+                        }
+                    }
+                }
+                if (firstSeparatorExists != v_firstSeparatorExists) {
+                    v_firstSeparatorExists = firstSeparatorExists;
+                    return true;
+                } else {
+                    return false;
+                }
+            } else {
+                return false;
+            }
+        } else {
+            return true;
+        }
+    }
+    
+    function updateViewmodels() {
+        // create or delete viewmodels so we have the correct number of them
+        var numberOfAdditionalViewmodels = v_tableData.separators.length - v_viewmodels.length;
+        if (numberOfAdditionalViewmodels > 0) {
+            for (var i = 0; i < numberOfAdditionalViewmodels; ++i) {
+                v_viewmodels.push({
+                    "aligner1": new AlignerViewmodel(),
+                    "aligner2": new AlignerViewmodel(),
+                    "table": new TableViewmodel()
+                });
+            }
+        } else if (numberOfAdditionalViewmodels < 0) {
+            for (var i = 0; i > numberOfAdditionalViewmodels; --i) {
+                v_viewmodels.pop();
+            }
+        }
+        
+        // update the viewmodels, we now know that v_viewmodels.length == v_tableData.separators.length
+        v_tableData.separators.push({"index": v_tableData.table.length}); // a small trick so we avoid conditions below
+        for (var i = 0; i < v_viewmodels.length; ++i) {
+            v_viewmodels[i].aligner1.setData(v_tableData.separators[i].index, 0, v_options.numberOfElementsInFirstAligner);
+            v_viewmodels[i].aligner2.setData(v_tableData.separators[i].index, v_options.numberOfElementsInFirstAligner, v_options.numberOfElementsInSecondAligner);
+            v_viewmodels[i].table.setData(v_tableData.separators[i].index, v_options.numberOfElementsInFirstAligner + v_options.numberOfElementsInSecondAligner + 1, v_tableData.separators[i + 1].index - v_tableData.separators[i].index);
+        }
+        v_tableData.separators.pop();
+    }
+    
+    /** private Classes */
+    
+    // The mocked viewmodel for ElementRelay used in the element aligners
+    function AlignerViewmodel() {
+        var v_row;
+        var v_col;
+        var v_columnCount;
+        
+        this.setData = function(p_row, p_col, p_columnCount) {
+            v_row = p_row;
+            v_col = p_col;
+            v_columnCount = p_columnCount;
+        };
+        
+        this.select = function() {};
+        
+        this.getListWithElementInfo = function() {
+            var list = [];
+            for (var i = 0; i < v_columnCount; ++i) {
+                list.push({
+                    "element": v_header[v_col + i].heading,
+                    "val": v_tableData.table[v_row][v_col + i].val,
+                    "isWritable": v_tableData.table[v_row][v_col + i].isWritable,
+                });
+            }
+            return {
+                "values": list,
+                "selections": []
+            }
+        };
+        
+        this.getList = function() {
+            var list = [];
+            for (var i = 0; i < v_columnCount; ++i) {
+                list.push([
+                    [v_tableData.table[v_row][v_col + i].val, undefined, v_tableData.table[v_row][v_col + i].isWritable]
+                ]);
+            }
+            return list;
+        };
+        
+        this.setValue = function(dataPathIndex, value) {
+            base.setValue(v_row, v_col + dataPathIndex, value);
+        };
+        
+        this.getChildPercentagesFromFlex = v_flexAligner.getChildPercentagesFromFlex;
+    }
+    
+    // The mocked viewmodel for DynamicTable used in the tables
+    function TableViewmodel() {
+        var v_row;
+        var v_col;
+        var v_rowCount;
+        
+        this.setData = function(p_row, p_col, p_rowCount) {
+            v_row = p_row;
+            v_col = p_col;
+            v_rowCount = p_rowCount;
+        };
+        
+        this.select = function() {};
+        
+        this.getHeader = function() {
+            var header = mcopy(v_header.slice(v_col));
+            for (var i = 0; i < header.length; ++i) {
+                header[i].elementIndex = i;
+            }
+            return header;
+        };
+        
+        this.getName = function() {
+            return v_header[v_col].heading;
+        };
+        
+        this.getTable = function() {
+            var tableData = [];
+            for (var i = 0; i < v_rowCount; ++i) {
+                tableData.push(v_tableData.table[v_row + i].slice(v_col));
+            }
+            return {"table": tableData};
+        };
+        
+        this.setValue = function(row, col, value) {
+            base.setValue(v_row + row, v_col + col, value);
+        };
+        
+        this.getChildPercentagesFromFlex = v_flexAligner.getChildPercentagesFromFlex;
+    }
+}
+
+CViewModel_Clients.getHelp = function() {
+    return "Viewmodel for the clients tab. Will return a list whose elements contain 3 viewmodels: 2 for aligners and one for a table.\n" + 
+        "A data connection for the possible size of the tables must precede the connection representing the 'iterator' of the table.";
+};
+
+CViewModel_Clients.providesInterface = function() {
+    return ["getViewmodelBundle", "getRange", "getPosition", "setPosition", "getViewportSize", "isStreaming"];
+};
+
+CViewModel_Clients.getCustomDataSchema = function() {
+    var outerTableSchema = CViewModel_TableForLargeData.getCustomDataSchema();
+    
+    outerTableSchema.title = "Custom data for CViewModel_Clients";
+    outerTableSchema.properties["numberOfElementsInFirstAligner"] = {
+        "type": "integer"
+    };
+    outerTableSchema.properties["numberOfElementsInSecondAligner"] = {
+        "type": "integer"
+    };
+    // Why does outerTableSchema.properties.name = undefined not work???
+    delete outerTableSchema.properties.name;
+    
+    if (outerTableSchema.required == undefined) {
+        outerTableSchema.required = []
+    }
+    outerTableSchema.required.splice(0, 0, "separateBy", "numberOfElementsInFirstAligner", "numberOfElementsInSecondAligner");
+    
+    return outerTableSchema;
+};
+
+CViewModel_Clients.expectsConnection = function() {
+    return CViewModel_TableForLargeData.expectsConnection();
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_Clients.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_CodeEditor.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_CodeEditor.js
new file mode 100644
index 0000000..3711953
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_CodeEditor.js
@@ -0,0 +1,84 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_CodeEditor(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    var v_dataPaths = [];
+    
+    /** public functions - interface for parent */
+    
+    this.setSelectionToControl = function(p_selection) {};
+    this.setBinder = function(p_binder) {};
+    this.setReponseDataPath = function(p_index, p_path) {
+        v_dataPaths[p_index] = p_path;
+    };
+	
+    /** public functions - interface for views */ 
+    
+    this.getTextData = function(callback) {
+        var returnValue;
+        var response = v_viewmodel.getResponseElement(v_dataPaths[0]);
+        if (response != undefined && response.node != undefined) {
+            if (response.node.tp == 5) {
+                callback(hex2a(response.node.val));
+            } else {
+                callback(response.node.val);
+            }
+        } else {
+            callback("");
+        }
+    };
+    
+    this.setTextData = function(text) {
+        var response = v_viewmodel.getResponseElement(v_dataPaths[0]);
+        if (response != undefined && response.node != undefined) {
+            if (response.node.tp == 5) {
+                v_viewmodel.setResponseElement(v_dataPaths[0], a2hex(text));
+            } else {
+                v_viewmodel.setResponseElement(v_dataPaths[0], text);
+            }
+        }
+    };
+}
+
+CViewModel_CodeEditor.getHelp = function() {
+    return "A viewmodel that can be used for editing code data.";
+}
+
+CViewModel_CodeEditor.providesInterface = function() {
+    return ["getTextData", "setTextData"];
+};
+
+CViewModel_CodeEditor.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_CodeEditor",
+        "type": "object",
+        "properties": {},
+        "additionalProperties": false
+    };
+};
+
+CViewModel_CodeEditor.expectsConnection = function() {
+    var dataConnections = [
+        {
+            "valueType": ["charstringType", "octetstringType"]
+        }
+    ];
+    
+    var selectionConnections = [];
+    
+    return {
+        "dataConnections": dataConnections,
+        "selectionConnections": selectionConnections
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_CodeEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Condition.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Condition.js
new file mode 100644
index 0000000..ab1a149
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Condition.js
@@ -0,0 +1,91 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_Condition(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    
+    var v_binder;
+    var v_dataPaths = [];
+    var v_selections = [];
+    
+    /** public functions - interface for parent */
+    
+    this.setSelectionToControl = function(p_selection) {
+        v_selections.push(p_selection);
+    };
+    
+    this.setReponseDataPath = function(p_index, p_path) {
+        v_dataPaths[p_index] = p_path;
+    };
+    
+    this.setBinder = function(p_binder) {
+        v_binder = p_binder;
+    };
+	
+    /** public functions - interface for views */ 
+    
+    this.getState = function() {
+        var returnValue;
+        var request = v_viewmodel.getRequestFromPath(v_dataPaths[0]);
+        var response = v_viewmodel.getResponseElement(v_dataPaths[0]);
+        if (response != undefined && response.node != undefined) {
+            if (response.node.tp == 0) {
+                returnValue = false;
+            } else if (response.node.tp == 3 && request.getData.filter == undefined) {
+                returnValue = response.node.val === "true";
+            } else {
+                returnValue = true;
+            }
+            if (v_options.negate) {
+                returnValue = !returnValue;
+            }
+        } else if (response != undefined && response.list != undefined) {
+            returnValue = response.list.length != 0;
+            if (v_options.negate) {
+                returnValue = !returnValue;
+            }
+        } else {
+            returnValue = false;
+        }
+        
+        return returnValue;
+    };
+}
+
+CViewModel_Condition.getHelp = function() {
+    return "This viewmodel can process a response element that can be used for conditions.\n" +
+        "If the element was filtered, the returned value is false.\n" +
+        "If the element does not contain a filter and it is a boolean value, the returned value will be the element's value.\n" +
+        "If the element is an empty list, it will be false.\n" +
+        "Otherwise, it is true";
+}
+
+CViewModel_Condition.providesInterface = function() {
+    return ["getState"];
+};
+
+CViewModel_Condition.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_Condition",
+        "type": "object",
+        "properties": {
+            "negate": {
+                "description": "whether we want to negate the condition",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            }
+        },
+        "additionalProperties": false
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\CViewModel_Condition.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_DistributionChart.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_DistributionChart.js
new file mode 100644
index 0000000..b284dcd
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_DistributionChart.js
@@ -0,0 +1,197 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_DistributionChart(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    
+    var v_dataPaths = [];
+    var v_visible = [];
+        
+    /** public functions - interface for parent */
+    
+    this.setSelectionToControl = function(p_selection) {};
+    this.setBinder = function(p_binder) {};
+    this.setReponseDataPath = function(p_index, p_path) {
+        v_dataPaths[p_index] = p_path;
+    };
+	
+    /** public functions - interface for views */
+    
+    this.getChartData = function() {
+        var data = getDatasetsAndNavigationData();
+        data.ticks = getTicks();
+        return data;
+    };
+    
+    this.toggleSeries = function(index) {
+        if (v_visible[index] == undefined) {
+            v_visible[index] = false;
+        } else {
+            v_visible[index] = !v_visible[index];
+        }
+    };
+    
+    this.isSeriesVisible = function(index) {
+        return v_visible[index] == undefined || v_visible[index] == true;
+    }
+    
+    /** private functions */
+    
+    function getTicks() {
+        var list = [];
+        if (v_options.intervallimits != undefined) {
+            list = v_options.intervallimits;
+        } else {
+            var response = v_viewmodel.getResponseElement(v_dataPaths[0]);
+            if (response != undefined && response.list != undefined) {
+                for (var i = 0; i < response.list.length; ++i) {
+                    list[i] = response.list[i].node.val;
+                }
+            }
+        }
+        
+        var listToReturn = [];
+        if (list.length > 0) {
+            listToReturn[0] = [1, "< " + list[0]];
+            listToReturn[list.length] = [list.length + 1, list[list.length - 1] + " <"];
+            for (var i = 0; i < list.length - 1; ++i) {
+                listToReturn[i + 1] = [i + 2, list[i] + " - " + list[i + 1]];
+            }
+        }
+        
+        return listToReturn;
+    }
+    
+    function getDatasetsAndNavigationData() {
+        var navigationData = {x: {pan: {min: -1, max: 1}, zoom: {min: 1, max: null}}, y: {pan: {min: -1, max: 1}, zoom: {min: 1, max: null}}};
+        var dataSets = [];
+        
+        var dataPathIndexOfValue = 0;
+        if (v_options.intervallimits == undefined && v_dataPaths.length > 1) {
+             dataPathIndexOfValue = 1;
+        }
+        
+        var counter = 0;
+        var response = v_viewmodel.getResponseElement(v_dataPaths[dataPathIndexOfValue]);
+        if (response != undefined && response.list != undefined) {
+            var request = v_viewmodel.getRequestFromPath(v_dataPaths[dataPathIndexOfValue]);
+            var dataSet = getEmptyDataSet(counter, request != undefined ? request.getData.element : "Series" + counter);
+
+            for (var j = 0; j < response.list.length; ++j) {
+                dataSet.data.push([j + 1, response.list[j].node.val]);
+            }
+            dataSets.push(dataSet);
+        }
+        
+        for (var i = 0; i < dataSets.length; ++i) {
+            navigationData.x.pan.max = Math.max(navigationData.x.pan.max, dataSets[i].data.length + 1);
+            for (var j = 0; j < dataSets[i].data.length; ++j) {
+                navigationData.y.pan.max = Math.max(navigationData.y.pan.max, dataSets[i].data[j][1] + 1);
+            }
+            dataSets[i].bars.barWidth = 0.8 / dataSets.length;
+        }
+        
+        return {
+            "dataSets": dataSets,
+            "navigationRanges": navigationData
+        }
+    }
+    
+    function getEmptyDataSet(counter, altLabel) {
+        var data;
+        if (v_options.dataSet == undefined || v_options.dataSet[counter] == undefined) {
+            data = {
+                "label": altLabel,
+                "data": [],
+                "lines": {
+                    "show": false
+                },
+                "bars": {
+                    "show": v_visible[counter] == undefined || v_visible[counter] == true,
+                    "barWidth": 0
+                }
+            }
+        } else {
+            data = {
+                "label": v_options.dataSet[counter].label,
+                "data": [],
+                "color": v_options.dataSet[counter].color,
+                "highlightColor": v_options.dataSet[counter].highlightColor,
+                "lines": {
+                    "show": false
+                },
+                "bars": {
+                    "show": v_visible[counter] == undefined || v_visible[counter] == true,
+                    "barWidth": 0
+                }
+            }
+        }
+        
+        return data;
+    }
+    
+}
+
+CViewModel_DistributionChart.getHelp = function() {
+    return "The viewmodel creates the data and labels for a distribution chart.\n" +
+        "Both the labels and values can come from a dataElement.\n" +
+        "If the custom data does not contain the intervallimits, the first data connection will be used to determine them.";
+};
+
+CViewModel_DistributionChart.providesInterface = function() {
+    return ["getChartData", "toggleSeries", "isSeriesVisible"];
+};
+
+CViewModel_DistributionChart.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_DistributionChart",
+        "type": "object",
+        "properties": {
+            "intervallimits": {
+                "description": "The predefined values for the interval limits of the distribution chart.",
+                "type": "array",
+                "format": "table",
+                "items": {
+                    "type": "number",
+                    "title": "limit"
+                }
+            },
+            "dataSet": {
+                "type": "array",
+                "format": "tabs",
+                "items": {
+                    "type": "object",
+                    "properties": {
+                        "label": {
+                            "type": "string",
+                            "description": "If present, it will be used as the label of the data."
+                        },
+                        "color": {
+                            "type": "string",
+                            "description": "If present, it will be used as the color of the data.",
+                            "pattern": "^#(?:[0-9a-fA-F]{3}){1,2}$"
+                        },
+                        "highlightColor": {
+                            "type": "string",
+                            "description": "If present, it will be used as the highlight color of the data.",
+                            "pattern": "^#(?:[0-9a-fA-F]{3}){1,2}$"
+                        }
+                    },
+                    "additionalProperties": false,
+                    "required": ["label"]
+                }
+            }
+        },
+        "additionalProperties": false
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_DistributionChart.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_DynamicTable.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_DynamicTable.js
new file mode 100644
index 0000000..65492b4
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_DynamicTable.js
@@ -0,0 +1,566 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_DynamicTable(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    if (v_options.iteratorColumnPosition == undefined) {
+        v_options.iteratorColumnPosition = 0;
+    }
+
+    var v_binder;
+    var v_dataPaths = [];
+    var v_selections = [];
+
+    var v_currentHeader = [];
+    // the view can use this info so that it can handle iterators in columns
+    var v_headerCounts = [];
+    // we store data so we can easily get the datapath, indexinlist and additional selections when a setdata occures
+    var v_setValueMatrix = [];
+
+    /** public functions - interface for parent */
+
+    this.setSelectionToControl = function(p_selection) {
+        v_selections.push(p_selection);
+    };
+
+    this.setReponseDataPath = function(p_index, p_path) {
+        v_dataPaths[p_index] = p_path;
+    };
+
+    this.setBinder = function(p_binder) {
+        v_binder = p_binder;
+    };
+
+	/** public functions - interface for views */
+
+    this.select = function(p_index) {
+        for (var i = 0; i < v_selections.length; ++i) {
+            v_viewmodel.select(v_selections[i], p_index);
+        }
+        if (v_selections.length > 0) {
+            v_binder.notifyChange(true);
+        }
+    };
+
+    this.getHeader = function() {
+        var counter = 0;
+        var header = [];
+        for (var i = 0; i < v_headerCounts.length; ++i) {
+            for (var j = 0; j < v_headerCounts[i]; ++j) {
+                var nextHeaderIndex = header.length;
+                header.push({
+                    "heading": v_currentHeader[nextHeaderIndex],
+                    "elementIndex": counter
+                });
+            }
+            ++counter;
+        }
+        return header;
+    };
+
+    this.getName = function() {
+        if (v_options.name != undefined) {
+            return v_options.name;
+        } else {
+            return v_viewmodel.getRequestFromPath(v_dataPaths[0]).getData.element;
+        }
+    };
+
+    this.getTable = function() {
+        var tableData = [];
+        var separators = [];
+
+        v_setValueMatrix = [];
+        v_currentHeader = [];
+        v_headerCounts = [];
+
+        var response = v_viewmodel.getResponseElement(v_dataPaths[0]);
+        if (response != undefined && response.list != undefined) {
+            // we store the previous row so we can determine if a separator is needed (an empty list will work in the beginning)
+            var previousRow = [];
+            // we will only create the header when we calculate the first row
+            var first = true;
+            for (var i = 0; i < response.list.length; ++i) {
+                var listElement = response.list[i];
+                var row = [];
+                var setValueMatrixRow = [];
+                fillRow(i, listElement, row, setValueMatrixRow, first);
+                tableData.push(row);
+                v_setValueMatrix.push(setValueMatrixRow);
+
+                // if we want separators, we add it, if the currect data in the row is not the same as in the previous row
+                if (v_options.separateBy != undefined) {
+                    var val;
+                    if (row[v_options.separateBy] != undefined) {
+                        val = row[v_options.separateBy].val;
+                    }
+                    var prevVal;
+                    if (previousRow[v_options.separateBy] != undefined) {
+                        prevVal = previousRow[v_options.separateBy].val
+                    }
+                    if (val != prevVal) {
+                        separators.push({
+                            "index": i,
+                            "text": row[v_options.separateBy].val
+                        });
+                    }
+                }
+
+                previousRow = row;
+                first = false;
+            }
+        }
+
+        if (v_options.transposeTable) {
+            tableData = transpose(tableData);
+            v_setValueMatrix = transpose(v_setValueMatrix);
+        }
+
+        if (v_options.iteratorIsHeader && tableData[0] != undefined) {
+            v_currentHeader = [];
+            for (var i = 0; i < tableData[0].length; ++i) {
+                v_currentHeader.push(tableData[0][i].val);
+            }
+            tableData.shift();
+            for (var i = 0; i < v_currentHeader.length; ++i) {
+                v_headerCounts[i] = 1;
+            }
+
+            while (v_headerCounts.length > v_currentHeader.length) {
+                v_headerCounts.pop();
+            }
+
+            v_setValueMatrix.shift();
+        }
+
+        return {
+            "table": tableData,
+            "selection": getSelectionIndexes(response),
+            "separators": separators
+        };
+    };
+
+    this.setValue = function(p_row, p_col, p_value, p_callback, p_additionalData) {
+        if (v_setValueMatrix[p_row] != undefined && v_setValueMatrix[p_row][p_col] != undefined) {
+            var dataPath = v_setValueMatrix[p_row][p_col].dataPath;
+            // they can be undefined, but that is ok
+            var indexInList = v_setValueMatrix[p_row][p_col].indexInList;
+            var additionalSelections = v_setValueMatrix[p_row][p_col].additionalSelections;
+            v_viewmodel.setResponseElement(dataPath, p_value, indexInList, additionalSelections, p_callback, p_additionalData);
+        }
+    };
+
+    /** private functions */
+
+    function fillRow(rowIndex, listElement, row, setValueRow, first) {
+        // the number of elements processed, used to tell whether we have to insert the iterator now (we do not want to isert it in the middle of an iterator)
+        var elementsProcessed = 0;
+        var request = v_viewmodel.getRequestFromPath(v_dataPaths[0]);;
+
+        if (first) {
+            // we only use the request in the header creation
+            //request = v_viewmodel.getRequestFromPath(v_dataPaths[0]);
+            tryToInsertIteratorHeader(request);
+        }
+
+        if (tryToInsertIteratorValue(rowIndex, row, setValueRow, listElement, elementsProcessed)) {
+            ++elementsProcessed;
+        }
+
+        if (v_dataPaths.length > 1) {
+            // if there are more than one data connections, than they represent the columns
+            fillRowMultipleDataPaths(rowIndex, listElement, row, setValueRow, first, request, elementsProcessed);
+        } else if (listElement.node.childVals != undefined) {
+            // the columns will be the children
+            fillRowOneDataPath(rowIndex, listElement, row, setValueRow, first, request, elementsProcessed);
+        } else {
+            // nothing to do
+        }
+    }
+
+    function createListFromChildVals(list) {
+        var value = [];
+        for (var i = 0; i < list.length; ++i) {
+            value.push(list[i].node.val);
+        }
+        return {"val": [value], "isWritable": false};
+    }
+
+    function fillRowOneDataPath(rowIndex, listElement, row, setValueRow, first, request, elementsProcessed) {
+        // we do not support manipulation and iterators in columns in this case
+        for (var i = 0; i < listElement.node.childVals.length; ++i) {
+            tryToInsertIteratorHeader(request)
+            if (tryToInsertIteratorValue(rowIndex, row, setValueRow, listElement, elementsProcessed)) {
+                ++elementsProcessed;
+            }
+
+            var childDataPath = mcopy(v_dataPaths[0]);
+            childDataPath.push(i);
+            if (first) {
+                if (request.getData.children != undefined && request.getData.children[i] != undefined) {
+                    v_currentHeader.push(getHeaderValue(request.getData.children[i].getData.element, v_headerCounts.length));
+                } else {
+                    v_currentHeader.push("");
+                }
+                v_headerCounts.push(1);
+            }
+
+            if (listElement.node.childVals[i].node != undefined) {
+                if (listElement.node.childVals[i].node.tp == 0) {
+                    row.push({"val": undefined, "isWritable": false, "tp": 0});
+                } else {
+                    row.push({"val": listElement.node.childVals[i].node.val, "isWritable": listElement.node.childVals[i].node.tp > 0, "tp": listElement.node.childVals[i].node.tp});
+                }
+            } else if (listElement.node.childVals[i].list != undefined) {
+                row.push(createListFromChildVals(listElement.node.childVals[i].list));
+            } else {
+                continue;
+            }
+
+            setValueRow.push({
+                "dataPath": childDataPath,
+                "additionalSelections": [rowIndex]
+            });
+            ++elementsProcessed;
+        }
+    }
+
+    function fillRowMultipleDataPaths(rowIndex, listElement, row, setValueRow, first, p_request, elementsProcessed) {
+        for (var i = 1; i < v_dataPaths.length; ++i) {
+            var request = p_request;
+
+            tryToInsertIteratorHeader(p_request)
+            if (tryToInsertIteratorValue(rowIndex, row, setValueRow, listElement, elementsProcessed)) {
+                ++elementsProcessed;
+            }
+
+            var found = true;
+            var responseNode = listElement;
+
+            var responseList = [];
+            var headerInfo;
+            // we try to find the data belonging to the current iterator value and the current datapath by going down the response tree
+            for (var j = v_dataPaths[0].length; j < v_dataPaths[i].length; ++j) {
+                if (responseNode.node != undefined && responseNode.node.childVals != undefined && responseNode.node.childVals[v_dataPaths[i][j]] != undefined) {
+                    // if the currently examined response is a node and it has the correct child
+                    responseNode = responseNode.node.childVals[v_dataPaths[i][j]];
+                    if (request != undefined && request.getData.children != undefined) request = request.getData.children[v_dataPaths[i][j]];
+                } else if (responseNode.list != undefined) {
+                    if (request != undefined && request.getData.selection != undefined && request.getData.selection[0] != undefined) {
+                        responseNode = responseNode.list[request.getData.selection[0]].node.childVals[v_dataPaths[i][j]];
+                        if (request.getData.children != undefined) request = request.getData.children[v_dataPaths[i][j]];
+                    } else if (request != undefined && request.getData.selectionValues != undefined) {
+                        responseNode = responseNode.list[0].node.childVals[v_dataPaths[i][j]];
+                        if (request.getData.children != undefined) request = request.getData.children[v_dataPaths[i][j]];
+                    } else {
+                        headerInfo = responseNode;
+                        // if the currently examined response is a list
+                        for (var k = 0; found && k < responseNode.list.length; ++k) {
+                            var responseNodeInList = responseNode.list[k];
+                            // we go deeper in the tree util we find each element that belongs to the datapath
+                            for (var l = j; found && l < v_dataPaths[i].length; ++l) {
+                                if (responseNodeInList.node != undefined && responseNodeInList.node.childVals != undefined && responseNodeInList.node.childVals[v_dataPaths[i][l]] != undefined && responseNodeInList.node.childVals[v_dataPaths[i][l]].node != undefined) {
+                                    // if the currently examined response is a node and it has the correct child
+                                    responseNodeInList = responseNodeInList.node.childVals[v_dataPaths[i][l]];
+                                } else if (responseNodeInList.node != undefined && responseNodeInList.node.childVals != undefined && responseNodeInList.node.childVals[v_dataPaths[i][l]] != undefined && responseNodeInList.node.childVals[v_dataPaths[i][l]].list != undefined) {
+                                    responseNodeInList = responseNodeInList.node.childVals[v_dataPaths[i][l]];
+                                } else {
+                                    found = false;
+                                }
+                                if (request != undefined && request.getData.children != undefined) request = request.getData.children[v_dataPaths[i][l]];
+                            }
+
+                            if (found) {
+                                responseList[k] = responseNodeInList;
+                            }
+                        }
+
+                        // we no longer need the response node, we either found the correct answer or failed
+                        responseNode = undefined;
+                        break;
+                    }
+                } else {
+                    found = false;
+                    break;
+                }
+            }
+
+            if (found) {
+                // we do not want to find a list element
+                if (responseNode != undefined) {
+                    // we found a single node (that can also be a list... but the path points to it instead of a descendant)
+                    var value = getValue(responseNode, i);
+                    row.push(value);
+                    setValueRow.push({
+                        "dataPath": v_dataPaths[i],
+                        "additionalSelections": [rowIndex]
+                    });
+                    ++elementsProcessed;
+                    if (first) {
+                        v_currentHeader.push(getHeaderValue(v_viewmodel.getRequestFromPath(v_dataPaths[i]).getData.element, v_headerCounts.length));
+                        v_headerCounts.push(1);
+                    }
+                } else if (responseList != undefined) {
+                    // we found the children of some list element
+                    for (var j = 0; j < responseList.length; ++j) {
+                        var value = getValue(responseList[j], i);
+                        row.push(value);
+                        setValueRow.push({
+                            "dataPath": v_dataPaths[i],
+                            "additionalSelections": [rowIndex, j]
+                        });
+                        ++elementsProcessed;
+                        if (first) {
+                            v_currentHeader.push(getHeaderValue(headerInfo.list[j].node.val, v_headerCounts.length));
+                        }
+                    }
+                    if (first) {
+                        v_headerCounts.push(responseList.length);
+                    }
+                }
+            }
+        }
+    }
+
+    function tryToInsertIteratorHeader(request) {
+        if (v_options.iteratorColumnPosition == v_headerCounts.length) {
+            v_currentHeader.push(getHeaderValue(request.getData.element, v_headerCounts.length));
+            v_headerCounts.push(1);
+        }
+    }
+
+    function tryToInsertIteratorValue(rowIndex, row, setValueRow, listElement, elementsProcessed) {
+        if (v_options.iteratorColumnPosition == elementsProcessed) {
+            row.push(getValue(listElement, 0));
+            setValueRow.push({
+                "dataPath": v_dataPaths[0],
+                "indexInList": rowIndex
+            });
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    function getHeaderValue(value, headerIndex) {
+        if (v_options.header == undefined || v_options.header[headerIndex] == undefined) {
+            return replaceValueInText(value, "#");
+        } else {
+            return replaceValueInText(value, v_options.header[headerIndex]);
+        }
+    }
+
+    function getValue(content, dataPathIndex) {
+        var value;
+        if (content.node != undefined) {
+            var node = content.node;
+            if (node.tp == 0) {
+                value = {"val": undefined, "isWritable": false, "tp": 0};
+            } else if (v_dataPaths.length > 1 && v_options.dataManipulator != undefined && v_options.dataManipulator[dataPathIndex] != undefined) {
+                if (v_options.dataManipulator[dataPathIndex].text != undefined) {
+                    value = {"val": replaceValueInText(node.val, v_options.dataManipulator[dataPathIndex].text), "isWritable": node.tp > 0, "tp": node.tp};
+                } else if (v_options.dataManipulator[dataPathIndex].excludeFromDisplay === true) {
+                    value = undefined;
+                } else {
+                    value = {"val": node.val, "isWritable": node.tp > 0, "tp": node.tp};
+                }
+            } else {
+                value = {"val": node.val, "isWritable": node.tp > 0, "tp": node.tp};
+            }
+        } else if (content.list != undefined) {
+            value = createListFromChildVals(content.list);
+        }
+
+        return value;
+    }
+
+    function replaceValueInText(p_value, p_text) {
+        var text = mcopy(p_text);
+        for (var i = text.length - 1; i >= 0; --i) {
+            // replace ## with #
+            if (text[i] == "#" && i != 0 && text[i-1] == "#") {
+                text = text.splice(i, 1);
+                --i;
+            } else if (text[i] == "#") {
+                text = text.splice(i, 1, p_value);
+            }
+        }
+        return text;
+    }
+
+    function getSelectionIndexes(response) {
+        if (v_selections[0] != undefined && response != undefined && response.list != undefined) {
+            if (v_selections[0].selectionValues != undefined) {
+                var selection = [];
+                for (var i = 0; i < v_selections[0].selectionValues.length; ++i) {
+                    for (var j = 0; j < response.list.length; ++j) {
+                        if (v_selections[0].selectionValues[i] == response.list[j].node.val) {
+                            selection.push(j);
+                        }
+                    }
+                }
+                return selection;
+            } else {
+                return v_selections[0].selection;
+            }
+        } else {
+            return undefined;
+        }
+    }
+}
+
+CViewModel_DynamicTable.getHelp = function() {
+    return "A table viewmodel. The first data connection must be a list which defines the rows of the table.\nIf more connections are given, they will represent the columns of the table.\n";
+};
+
+CViewModel_DynamicTable.providesInterface = function() {
+    return ["select", "getName", "getHeader", "getTable", "setValue"];
+};
+
+CViewModel_DynamicTable.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_DynamicTable",
+        "type": "object",
+        "properties": {
+            "name": {
+                "description": "The title of the table",
+                "type": "string"
+            },
+            "header": {
+                "description": "The header of the table. It should have as many elements as the number of columns. Use # to refer to element name of the request (or in case of iterators, the parent request's response) that will be in the corresponding column.",
+                "type": "array",
+                "format": "table",
+                "items": {
+                    "type": "string",
+                    "title": "heading",
+                    "default": "#"
+                }
+            },
+            "iteratorColumnPosition": {
+                "description": "Insert the data from the connected iterator to this column (-1 if the table should not contain the values of the iterator).",
+                "type": "integer",
+                "default": -1,
+                "min": -1
+            },
+            "iteratorIsHeader": {
+                "description": "Whether the values from the iterator will be used as the header.",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            },
+            "transposeTable": {
+                "description": "Whether the table is transposed.",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            },
+            "separateBy": {
+                "description": "The index of the column by which the data will be separated.",
+                "type": "integer",
+                "default": 0,
+                "min": 0
+            },
+            "dataManipulator": {
+                "descriptor": "A list of rules that can manipulate the data obtained from the dataconnections of the table. It will only be processed if more than one dataConnection exists.",
+                "type": "array",
+                "format": "tabs",
+                "items": {
+                    "oneOf": [
+                        {
+                            "type": "object",
+                            "title": "noManipulation",
+                            "properties": {},
+                            "additionalProperties": false
+                        },
+                        {
+                            "type": "object",
+                            "title": "condition",
+                            "properties": {
+                                "condition": {
+                                    "description": "The definition of a condition. The value of the parent request will be used (it must return a boolean).",
+                                    "type": "object",
+                                    "properties": {
+                                        "true": {
+                                            "description": "The text to show when the condition is true.",
+                                            "type": "string"
+                                        },
+                                        "false": {
+                                            "description": "The text to show when the condition is false.",
+                                            "type": "string"
+                                        }
+                                    },
+                                    "default": {}
+                                }
+                            },
+                            "additionalProperties": false,
+                            "required": ["condition"]
+                        },
+                        {
+                            "type": "object",
+                            "title": "text",
+                            "properties": {
+                                "text": {
+                                    "description": "The text to be inserted into the table. The data of this connection can be referred to as # (to escape it, use two hashmarks). If omitted, only the data will be inserted.",
+                                    "type": "string"
+                                }
+                            },
+                            "additionalProperties": false,
+                            "required": ["text"]
+                        },
+                        {
+                            "type": "object",
+                            "title": "excludeFromDisplay",
+                            "properties": {
+                                "excludeFromDisplay": {
+                                    "description": "To exclude the data from this dataconnection from being inserted into the table as a column. (Not applicable for the iterator connection, use iteratorColumnPosition = -1 instead.)",
+                                    "type": "boolean",
+                                    "format": "checkbox",
+                                    "default": true
+                                }
+                            },
+                            "additionalProperties": false,
+                            "required": ["excludeFromDisplay"]
+                        }
+                    ]
+                }
+            }
+        },
+        "additionalProperties": false
+    };
+};
+
+CViewModel_DynamicTable.expectsConnection = function() {
+    var dataConnections = [
+        {
+            "valueType": ["charstringlistType", "integerlistType", "floatlistType"]
+        },
+        {
+            "childOfDataConnection": 0,
+            "multiple": true,
+            "optional": true
+        }
+    ];
+
+    var selectionConnections = [
+        {
+            "dataElementOfDataConnection": 0,
+            "multiple": true,
+            "optional": true
+        }
+    ];
+
+    return {
+        "dataConnections": dataConnections,
+        "selectionConnections": selectionConnections
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_DynamicTable.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_ElementRelay.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_ElementRelay.js
new file mode 100644
index 0000000..b00e201
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_ElementRelay.js
@@ -0,0 +1,287 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_ElementRelay(aViewModel, aOptions)
+{
+    "use strict";
+    /** private members */
+    var mViewModel;
+    var mOptions;
+    var mRq;
+    var mBinder;
+    var mReponseDataPaths;
+    var mSelections = []; // mSelectionss is a list of references to objects, each containing a field named "selection"
+    
+    /** constructor */
+    mViewModel = aViewModel;
+    mRq = mViewModel.getRequest();
+    mOptions = aOptions;
+    mReponseDataPaths = [];
+
+    /** public functions - Interface for parent */ 
+    this.expectedReponseData = function() // TODO: might be put in prototype (without header info)
+    {
+        return[{type: "elementRelay"}, {type: "string"}];
+    };
+
+    this.setSelectionToControl = function(aSelection)
+    {
+        mSelections.push(aSelection);
+    };
+    
+    this.setReponseDataPath = function(aDataPathIndex, aReponseDataPath)
+    {
+        mReponseDataPaths[aDataPathIndex] = aReponseDataPath;
+    };
+    
+    this.setBinder = function(aBinder)
+    {
+        mBinder = aBinder;
+    };
+	
+	/** public functions - Interface for views */ 
+    this.select = function(aIndex)
+    {
+        for (var i = 0; i < mSelections.length; ++i)
+            mViewModel.select(mSelections[i], aIndex);
+        mBinder.notifyChange(true);
+    };
+
+    this.getOptions = function()
+    {
+        return mOptions;
+    };
+    
+    this.getList = function()
+    {
+        return prepareResponse(getSimpleDataFromResponseElement);
+    };
+    
+    this.getListWithElementInfo = function()
+    {
+        return prepareResponse(getDataFromResponseElement);
+    };
+
+    this.setValue = function(aDataPathIndex, aValue, aIndexInList, aLastSelectionIndexes, aDataHasBeenSet, aAdditionalData)
+    {
+        mViewModel.setResponseElement(mReponseDataPaths[aDataPathIndex], aValue, aIndexInList, aLastSelectionIndexes, aDataHasBeenSet, aAdditionalData);
+    };
+
+    /** private functions */
+
+    function prepareResponse(aGetValueFunction)
+    {
+        var lValues = [];
+        var lSelections = [];
+        for (var i = 0; i < mReponseDataPaths.length; ++i)
+        {
+            lValues[i] = aGetValueFunction(mViewModel.getResponseElement(mReponseDataPaths[i]), mViewModel.getRequestFromPath(mReponseDataPaths[i]));
+        }
+        for (var i = 0; i < mSelections.length; ++i)
+        {
+            lSelections[i] = mSelections[i] ? mSelections[i].selection : undefined;
+        }
+        return {
+            selections: lSelections,
+            values: lValues
+        };
+    }
+
+    
+    function getRow(node)
+    {
+        var row = [];
+        row.push(node.val);
+        if (node.childVals)
+        {
+            var lChildren = [];
+            for (var j = 0; j < node.childVals.length; ++j)
+            {
+                if (node.childVals[j].node)
+                {
+                    lChildren.push(node.childVals[j].node.val);
+                }
+                else if (node.childVals[j].list)
+                {
+                    var lList = [];
+                    for (var i = 0; i < node.childVals[j].list.length; ++i)
+                        lList.push(node.childVals[j].list[i].node.val);
+                    lChildren.push(lList);
+                    //console.log ("lListVM::", lList);
+                }
+            }
+            row.push(lChildren);
+        }
+        return row;
+    }
+    
+    function getSimpleDataFromResponseElement(lElement, aRq)
+    {
+        var lTable = [];
+        if (lElement)
+        {
+            if (lElement.error)
+                lTable.push([lElement.error]);
+            else if (lElement.node)
+                lTable.push(getRow(lElement.node));
+            else if (lElement.list)
+            {
+                /*if (mSelections[0] && mSelections[0][0] >= lElement.list.length)
+                    mSelections[0][0] = 0;*/
+                if (mOptions.showOnlySelected != undefined && aRq.getData.selection != undefined) {
+                    if (lElement.list.length > 0) {
+                        if (aRq.getData.selectionValues != undefined) {
+                            lTable.push(getRow(lElement.list[0].node));
+                        } else {
+                            lTable.push(getRow(lElement.list[aRq.getData.selection[0]].node));
+                        }
+                    }
+                } else {
+                    for (var i = 0; i < lElement.list.length; ++i) {
+                        lTable.push(getRow(lElement.list[i].node));
+                    }
+                }
+            }
+            //else
+                //console.log("something else lElement: ", lElement)
+        }
+        return lTable;
+    }
+
+    function getChildren(node)
+    {
+        var lChildren = [];
+        if (node.childVals)
+        {
+            for (var j = 0; j < node.childVals.length; ++j)
+            {
+                if (node.childVals[j].node)
+                {
+                    lChildren.push(node.childVals[j].node.val);
+                }
+                else if (node.childVals[j].list)
+                {
+                    var lList = [];
+                    for (var i = 0; i < node.childVals[j].list.length; ++i)
+                        lList.push(node.childVals[j].list[i].node.val);
+                    lChildren.push(lList);
+                }
+            }
+        }
+        return lChildren;
+    }
+
+    function getDataFromResponseElement(lElement, aRq)
+    {
+        var lData = {};
+        if (lElement)
+        {
+            lData.element = aRq.getData.element;
+            lData.selection = aRq.getData.selection;
+            if (lElement.error)
+                lData.error = lElement.error;
+            else if (lElement.node)
+            {
+                lData.val = lElement.node.val;
+                lData.isWritable = lElement.node.tp > 0;
+                lData.children = getChildren(lElement.node, aRq.getData)[1];
+            }
+            else if (lElement.list)
+            {
+
+                if (mOptions.showOnlySelected != undefined && aRq.getData.selection != undefined) {
+                    if (lElement.list.length > 0) {
+                        var node;
+                        var lChildList = [];
+                        if (aRq.getData.selectionValues != undefined) {
+                            node = lElement.list[0].node
+                        } else {
+                            
+                            node = lElement.list[aRq.getData.selection[0]].node;
+                        }
+                        lData.val = node.val;
+                        if (aRq.getData.children) {
+                            var lChildren = getChildren(node);
+                            if (aRq.getData.children) {
+                                for (var j = 0; j < lChildren.length; ++j) {
+                                    lChildList[j] = {
+                                        element: aRq.getData.children[j].getData.element, 
+                                        val:[lChildren[j]],
+                                        selection: aRq.getData.children[j].getData.selection
+                                    };
+                                }
+                            }
+                        }
+                        lData.children = lChildList;
+                    } else {
+                        lData.val = "";
+                        lData.children = [];
+                    }
+                } else {
+                    var lList = [];
+                    var lChildList = [];
+                    
+                    for (var i = 0; i < lElement.list.length; ++i) {
+                        lList.push(lElement.list[i].node.val);
+                        var lChildren = getChildren(lElement.list[i].node);
+                        if (aRq.getData.children)
+                        {
+                            if (lChildList.length == 0)
+                            {
+                                for (var j = 0; j < lChildren.length; ++j)
+                                {
+                                    lChildList[j] = {
+                                        element: aRq.getData.children[j].getData.element, 
+                                        val:[],
+                                        selection: aRq.getData.children[j].getData.selection
+                                    };
+                                }
+                            }
+                            for (var j = 0; j < lChildren.length; ++j)
+                            {
+                                lChildList[j].val.push(lChildren[j]);
+                            }
+                        }
+                    }
+                    
+                    lData.val = lList;
+                    lData.children = lChildList;
+                }
+                
+
+            }
+        }
+        return lData;
+    }
+}
+
+CViewModel_ElementRelay.getHelp = function() {
+    var help = 'Simple interface for views.\n';
+    help += 'The function getList will return the following structure: {values: [[value, [children], isWritable]], selections: [[]]}\n';
+    help += 'The function getListWithElementInfo will return the following structure: {values: [{val: "", element: "", isWritable: boolean, selection: [], children: []}], selections: [[]]}\n';
+    return help;
+}
+
+CViewModel_ElementRelay.providesInterface = function() {
+    return ["setValue", "getListWithElementInfo", "getList", "getOptions", "select"];
+};
+
+CViewModel_ElementRelay.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_ElementRelay",
+        "type": "object",
+        "properties": {
+            "showOnlySelected": {
+                "type": "boolean",
+                "format": "checkbox",
+                "description": "whther we only show the selected element from an iterator",
+                "default": true
+            }
+        }
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_ElementRelay.js
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_FlexAligner.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_FlexAligner.js
new file mode 100644
index 0000000..98f852d
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_FlexAligner.js
@@ -0,0 +1,118 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_FlexAligner(p_viewModel, p_options) {
+    "use strict";
+    
+    /** constructor */
+    
+    var v_viewmodel = p_viewModel;
+    var v_options = p_options;
+    var v_binder;
+    
+    var v_this = this;
+    
+    /** public functions - interface for parent */ 
+    
+    this.setBinder = function(p_binder) {
+        v_binder = p_binder;
+    };
+    
+    /** public functions - interface for views */ 
+    
+    this.getChildPercentages = function(p_ids) {
+        var total = 0;
+        var flexes = [];
+        for (var i = 0; i < p_ids.length; ++i) {
+            flexes.push(1);
+        }
+        
+        var descriptors = v_viewmodel.getViewDescriptors();
+        for (var i = 0; i < descriptors.length; ++i) {
+            var index = p_ids.indexOf(descriptors[i].parentID);
+            if (index != -1) {
+                var flex = descriptors[i].customData.flex;
+                if (flex != undefined) {
+                    flexes[index] = flex;
+                    total += flex;
+                } else {
+                    total += 1;
+                }
+            }
+        }
+        
+        v_this.getChildPercentagesFromFlex(flexes, total);
+        
+        return flexes;
+    };
+    
+    this.getChildPercentagesFromFlex = function(flexes, total) {
+        for (var i = 0; i < flexes.length; ++i) {
+            flexes[i] = "" + ((flexes[i] / total) * 100) + "%";
+        }
+    };
+    
+    this.getChildSizes = function(p_ids) {
+        var totalFlex = 0;
+        var totalPx = 0;
+        var sizes = [];
+        for (var i = 0; i < p_ids.length; ++i) {
+            sizes.push(1);
+        }
+        
+        var descriptors = v_viewmodel.getViewDescriptors();
+        for (var i = 0; i < descriptors.length; ++i) {
+            var index = p_ids.indexOf(descriptors[i].parentID);
+            if (index != -1) {
+                var flex = descriptors[i].customData.flex;
+                if (flex != undefined) {
+                    sizes[index] = flex;
+                    if (Number.isInteger(flex)) {
+                        totalFlex += flex;
+                    } else {
+                        totalPx += parseInt(flex.substring(0, flex.length - 2));
+                    }
+                } else {
+                    totalFlex += 1;
+                }
+            }
+        }
+        
+        for (var i = 0; i < sizes.length; ++i) {
+            if (Number.isInteger(sizes[i])) {
+                sizes[i] = "calc(" + (100 * sizes[i] / totalFlex) + "% - " + totalPx + "px)";
+            }
+        }
+        
+        return sizes;
+    };
+}
+
+CViewModel_FlexAligner.getHelp = function() {
+    return "A viewmodel that can calculate percentages from the flex of subviews.";
+}
+
+CViewModel_FlexAligner.providesInterface = function() {
+    return ["getChildPercentages", "getChildPercentagesFromFlex", "getChildSizes"];
+};
+
+CViewModel_FlexAligner.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_FlexAligner",
+        "type": "object",
+        "properties": {},
+        "additionalProperties": false
+    };
+};
+
+CViewModel_FlexAligner.expectsConnection = function() {
+    return {
+        "dataConnections": [],
+        "selectionConnections": []
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_FlexAligner.js
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_JSONEditor.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_JSONEditor.js
new file mode 100644
index 0000000..6ff3a51
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_JSONEditor.js
@@ -0,0 +1,105 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_JSONEditor(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    var v_dataPaths = [];
+
+    /** public functions - interface for parent */
+
+    this.setSelectionToControl = function(p_selection) {};
+    this.setBinder = function(p_binder) {};
+    this.setReponseDataPath = function(p_index, p_path) {
+        v_dataPaths[p_index] = p_path;
+    };
+
+    /** public functions - interface for views */
+
+    this.getJSONData = function(callback) {
+        callback(getResponse(0));
+    };
+
+    this.setJSONData = function(json) {
+        var response = v_viewmodel.getResponseElement(v_dataPaths[0]);
+        if (response != undefined && response.node != undefined) {
+            if (response.node.tp == 5) {
+                v_viewmodel.setResponseElement(v_dataPaths[0], a2hex(JSON.stringify(json)));
+            } else {
+                v_viewmodel.setResponseElement(v_dataPaths[0], JSON.stringify(json));
+            }
+        }
+    };
+
+    this.getSchema = function() {
+        if (v_dataPaths.length > 1) {
+            return getResponse(1);
+        } else {
+            return v_options.schema;
+        }
+    };
+
+    function getResponse(index) {
+        var returnValue;
+        var response = v_viewmodel.getResponseElement(v_dataPaths[index]);
+        if (response != undefined && response.node != undefined) {
+            if (response.node.tp == 5) {
+                return JSON.parse(hex2a(response.node.val));
+            } else {
+                return JSON.parse(response.node.val);
+            }
+        } else {
+            return {};
+        }
+    }
+}
+
+CViewModel_JSONEditor.getHelp = function() {
+    return "A viewmodel that can be used for editing json data using a json schema.";
+}
+
+CViewModel_JSONEditor.providesInterface = function() {
+    return ["getJSONData", "setJSONData", "getSchema"];
+};
+
+CViewModel_JSONEditor.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_JSONEditor",
+        "type": "object",
+        "properties": {
+            "schema": {
+                "description": "The json schema that the json editor will use if a second data connection is not present.",
+                "type": "object"
+            }
+        },
+        "additionalProperties": false
+    };
+};
+
+CViewModel_JSONEditor.expectsConnection = function() {
+    var dataConnections = [
+        {
+            "valueType": ["charstringType", "octetstringType"]
+        },
+        {
+            "valueType": ["charstringType", "octetstringType"],
+            "optional": true
+        }
+    ];
+
+    var selectionConnections = [];
+
+    return {
+        "dataConnections": dataConnections,
+        "selectionConnections": selectionConnections
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_CodeEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Multiplier.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Multiplier.js
new file mode 100644
index 0000000..ac5470c
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Multiplier.js
@@ -0,0 +1,218 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_Multiplier(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    
+    var v_binder;
+    var v_dataPaths = [];
+    
+    var v_currentBundle = [];
+    
+    var v_this = this;
+    
+    /** public functions - interface for parent */ 
+
+    this.setSelectionToControl = function() {};
+    
+    this.setReponseDataPath = function(p_index, p_path) {
+        v_dataPaths[p_index] = p_path;
+    };
+    
+    this.setBinder = function(p_binder) {
+        v_binder = p_binder;
+    };
+	
+	/** public functions - interface for views */ 
+
+    this.getViewmodelBundle = function() {
+        var response = v_viewmodel.getResponseElement(v_dataPaths[0]);
+        var numberOfBundles = 0;
+        if (response != undefined && response.list != undefined) {
+            numberOfBundles = response.list.length;
+        }
+        
+        var currentBundles = v_currentBundle.length;
+        if (numberOfBundles < currentBundles) {
+            while (v_currentBundle.length > numberOfBundles) {
+                v_currentBundle.pop();
+            }
+        } else if (numberOfBundles > currentBundles) {
+            for (var i = currentBundles; i < numberOfBundles; ++i) {
+                v_currentBundle.push(createBundle(i));
+            }
+        }
+        
+        return v_currentBundle;
+    };
+
+    /** private functions */
+    
+    function createBundle(indexInList) {
+        var bundle = [];
+        if (v_options.subviewmodels != undefined) {
+            for (var i = 0; i < v_options.subviewmodels.length; ++i) {
+                if (v_options.subviewmodels[i].subViewmodel != undefined && window[v_options.subviewmodels[i].subViewmodel] != undefined) {
+                    if (v_options.subviewmodels[i].subViewmodelType == "ViewmodelForIteratorViewmodels") {
+                        bundle[i] = new window[v_options.subviewmodels[i].subViewmodel](new ViewmodelForIteratorViewmodels(indexInList), v_options.subviewmodels[i]);
+                    } else {
+                        bundle[i] = new window[v_options.subviewmodels[i].subViewmodel](new ViewmodelForsubviewmodels(indexInList), v_options.subviewmodels[i]);
+                    }
+                    
+                    if (v_options.subviewmodels[i].dataPathIndexes != undefined) {
+                        for (var j = 0; j < v_options.subviewmodels[i].dataPathIndexes.length; ++j) {
+                            if (bundle[i].setReponseDataPath != undefined) {
+                                bundle[i].setReponseDataPath(j, v_dataPaths[v_options.subviewmodels[i].dataPathIndexes[j]]);
+                            }
+                            if (bundle[i].setBinder != undefined) {
+                                bundle[i].setBinder(v_binder);
+                            }
+                            bundle[i].loadFile = v_this.loadFile;
+                        }
+                    }
+                    
+                } else {
+                    alert("No class found for subviewmodel " + i + ": " + v_options.subviewmodels[i].subViewmodel);
+                }
+            }
+        }
+        return bundle;
+    }
+    
+    /** private Classes */
+    
+    function ViewmodelForIteratorViewmodels(indexInList) {
+        var v_indexInList = indexInList;
+        
+        for (var id in v_viewmodel) {
+            if (v_viewmodel.hasOwnProperty(id)) {
+                this[id] = v_viewmodel[id];
+            }
+        }
+        
+        this.getResponseElement = function(reponseDataPath, lastSelectionIndexes) {
+            var response = v_viewmodel.getResponseElement(reponseDataPath, lastSelectionIndexes);
+            if (response != undefined && response.list != undefined) {
+                response = response.list[v_indexInList];
+            } else {
+                response = undefined;
+            }
+            return response;
+        };
+        
+        this.setResponseElement = function(reponseDataPath, value, indexInList, lastSelectionIndexes, callback) {
+            v_viewmodel.setResponseElement(reponseDataPath, value, v_indexInList, lastSelectionIndexes, callback);
+        };
+    }
+    
+    function ViewmodelForsubviewmodels(indexInList) {
+        var v_indexInList = indexInList;
+        
+        for (var id in v_viewmodel) {
+            if (v_viewmodel.hasOwnProperty(id)) {
+                this[id] = v_viewmodel[id];
+            }
+        }
+        
+        this.getResponseElement = function(reponseDataPath, lastSelectionIndexes) {
+            if (lastSelectionIndexes != undefined) {
+                lastSelectionIndexes.unshift(v_indexInList);
+            } else {
+                lastSelectionIndexes = [v_indexInList];
+            }
+            return v_viewmodel.getResponseElement(reponseDataPath, lastSelectionIndexes);
+        };
+        
+        this.setResponseElement = function(reponseDataPath, value, indexInList, lastSelectionIndexes, callback) {
+            if (lastSelectionIndexes != undefined) {
+                lastSelectionIndexes.unshift(v_indexInList);
+            } else {
+                lastSelectionIndexes = [v_indexInList];
+            }
+            v_viewmodel.setResponseElement(reponseDataPath, value, indexInList, lastSelectionIndexes, callback);
+        };
+    }
+}
+
+CViewModel_Multiplier.getHelp = function() {
+    return "Viewmodel that can be used to create other viewmodels based on the number of elements in an iterator.";
+};
+
+CViewModel_Multiplier.providesInterface = function() {
+    return ["getViewmodelBundle"];
+};
+
+CViewModel_Multiplier.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_DynamicTable",
+        "type": "object",
+        "properties": {
+            "subviewmodels": {
+                "descriptor": "A list of sub viewmodels, including their custom data, that will be created for every element in the iterator.",
+                "type": "array",
+                "format": "tabs",
+                "items": {
+                    "type": "object",
+                    "title": "subViewmodel",
+                    "properties": {
+                        "subViewmodel": {
+                            "description": "The class name of the viewmodel.",
+                            "type": "string"
+                        },
+                        "dataPathIndexes": {
+                            "description": "Which connected data paths belong to this viewmodel?",
+                            "type": "array",
+                            "format": "table",
+                            "items": {
+                                "title": "viewmodel index",
+                                "type": "integer",
+                                "min": 0
+                            }
+                        },
+                        "subViewmodelType": {
+                            "description": "The type of the sub viewmodel. Use ViewmodelForIteratorViewmodels when using data path 0 for a label.",
+                            "type": "string",
+                            "enum": ["ViewmodelForIteratorViewmodels", "ViewmodelForsubviewmodels"],
+                            "default": "ViewmodelForIteratorViewmodels"
+                        }
+                    },
+                    "additionalProperties": true,
+                    "required": ["subViewmodel"]
+                },
+                "minItems": 1
+            }
+        },
+        "additionalProperties": false,
+        "required": ["subviewmodels"]
+    };
+};
+
+CViewModel_Multiplier.expectsConnection = function() {
+    var dataConnections = [
+        {
+            "valueType": ["charstringlistType", "integerlistType", "floatlistType"]
+        },
+        {
+            "childOfDataConnection": 0,
+            "multiple": true,
+            "optional": true
+        }
+    ];
+    
+    var selectionConnections = [];
+    
+    return {
+        "dataConnections": dataConnections,
+        "selectionConnections": selectionConnections
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_Multiplier.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Paging.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Paging.js
new file mode 100644
index 0000000..d02b6ba
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_Paging.js
@@ -0,0 +1,167 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_Paging(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    
+    var v_binder;
+    var v_dataPaths = [];
+    var v_selections = [];
+    
+    /** public functions - interface for parent */
+    
+    this.setSelectionToControl = function(p_selection) {
+        v_selections.push(p_selection);
+    };
+    
+    this.setReponseDataPath = function(p_index, p_path) {
+        v_dataPaths[p_index] = p_path;
+    };
+    
+    this.setBinder = function(p_binder) {
+        v_binder = p_binder;
+    };
+	
+	/** public functions - interface for views */ 
+    
+    this.getSize = function() {
+        var response = v_viewmodel.getResponseElement(v_dataPaths[0]);
+        if (response != undefined && response.node != undefined) {
+            return response.node.val;
+        } else {
+            return 0;
+        }
+    };
+    
+    this.getRangeFilter = function() {
+        var size = this.getSize();
+        var filter = v_viewmodel.getRequestFromPath(v_dataPaths[1]).getData.rangeFilter;
+        
+        if (filter == undefined) {
+            return {
+                "offset": 0,
+                "count": size
+            };
+        } else {
+            var offset = 0;
+            if (filter.offset != undefined) {
+                offset = filter.offset;
+            }
+            if (offset >= size) {
+                offset = Math.max(0, size - 1);
+            }
+            
+            var count;
+            if (filter.count != undefined) {
+                count = filter.count;
+            } else {
+                count = size - offset;
+            }
+
+            return {
+                "offset": offset,
+                "count": count
+            }
+        }
+    };
+    
+    this.changeFilter = function(obj) {
+        var getData = v_viewmodel.getRequestFromPath(v_dataPaths[1]).getData;
+        var filter = getData.rangeFilter;;
+        var size = this.getSize();
+        
+        if (obj == undefined) {
+            getData.rangeFilter = undefined;
+            return;
+        } else if (filter == undefined) {
+            filter = {};
+            getData.rangeFilter = filter;
+        }
+        
+        if (obj.offset != undefined) {
+            if (obj.offset.to != undefined) {
+                filter.offset = obj.offset.to;
+            } else if (obj.offset.by != undefined) {
+                if (filter.offset != undefined) {
+                    filter.offset += obj.offset.by;
+                } else {
+                    filter.offset = obj.offset.by;
+                }
+            }
+            if (filter.offset < 0) {
+                filter.offset = 0;
+            } else if (filter.count != undefined && v_options.allowScrollBelow == false && filter.offset > size - filter.count) {
+                filter.offset = Math.max(size - filter.count, 0);
+            } else if (filter.offset > size - 1) {
+                filter.offset = Math.max(size - 1, 0);
+            }
+        }
+        
+        if (obj.count != undefined) {
+            if (obj.count.to != undefined) {
+                filter.count = obj.count.to;
+            } else if (obj.count.by != undefined && filter.count != undefined) {
+                filter.count += obj.count.by;
+            }
+            
+            if (filter.count < 1) {
+                filter.count = 1;
+            }
+        }
+    };
+    
+    this.hasFilter = function() {
+        return v_viewmodel.getRequestFromPath(v_dataPaths[1]).getData.rangeFilter != undefined;
+    }
+}
+
+CViewModel_Paging.getHelp = function() {
+    return "A viewmodel that can manipulate the rangeFilter of a request.";
+}
+
+CViewModel_Paging.providesInterface = function() {
+    return ["getSize", "getRangeFilter", "changeFilter"];
+};
+
+CViewModel_Paging.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_Paging",
+        "type": "object",
+        "properties": {
+            "allowScrollBelow": {
+                "description": "Whether we want to allow paging to the very bottom (so that only one element remains unfiltered). Set it to false if the connected view can show every element.",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": false
+            }
+        },
+        "additionalProperties": false
+    };
+};
+
+CViewModel_Paging.expectsConnection = function() {
+    var dataConnections = [
+        {
+            "source": "DataSource",
+            "element": "sizeOf"
+        },
+        {
+            "valueType": ["charstringlistType", "integerlistType", "floatlistType"]
+        }
+    ];
+    
+    return {
+        "dataConnections": dataConnections,
+        "selectionConnections": []
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_Paging.js
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_RequestManipulator.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_RequestManipulator.js
new file mode 100644
index 0000000..3801814
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_RequestManipulator.js
@@ -0,0 +1,172 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_RequestManipulator(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    
+    var v_binder;
+    var v_dataPaths = [];
+    var v_selections = [];
+    
+    var v_request;
+    var v_schema = {
+        "$schema" : "http://json-schema.org/draft-04/schema#",
+        "definitions" : {
+            "getDataDef" : {
+                "title" : "request",
+                "type" : "object",
+                "additionalProperties" : false,
+                "properties" : {
+                    "getData": {
+                        "type": "object",
+                        "additionalProperties" : false,
+                        "properties": {
+                            "source": {
+                                "description": "The source",
+                                "type": "string"
+                            },
+                            "element": {
+                                "description": "The element",
+                                "type": "string"
+                            },
+                            "ptcname": {
+                                "description": "The ptc name",
+                                "type": "string"
+                            },
+                            "params": {
+                                "type": "array",
+                                "format": "table",
+                                "items": {
+                                    "type": "object",
+                                    "title": "Parameter",
+                                    "properties": {
+                                        "paramName" : {
+                                            "type" : "string"
+                                        },
+                                        "paramValue" : {
+                                            "type" : "string"
+                                        }
+                                    },
+                                    "additionalProperties": false
+                                },
+                                "uniqueItems": true
+                            },
+                            "selection": {
+                                "type": "array",
+                                "format": "table",
+                                "items": {
+                                    "type": "integer",
+                                    "minimum": "0",
+                                    "title": "Selection item"
+                                },
+                                "uniqueItems": true
+                            },
+                            "selectionValues": {
+                                "type": "array",
+                                "format": "table",
+                                "items": {
+                                    "type": "string",
+                                    "title": "Selected value"
+                                }
+                            },
+                            "rangeFilter": {
+                                "type": "object",
+                                "properties": {
+                                    "offset": {
+                                        "type": "integer",
+                                        "minimum": 0
+                                    },
+                                    "count": {
+                                        "type": "integer",
+                                        "minimum": 0
+                                    }
+                                },
+                                "additionalProperties": false
+                            },
+                            "children" : {
+                                "type" : "array",
+                                "additionalProperties" : false,
+                                "items" : {
+                                    "$ref" : "#/definitions/getDataDef"
+                                }
+                            }
+                        },
+                        "required" : [
+                            "source",
+                            "element"
+                        ]
+                    }
+                },
+                "required" : ["getData"]
+            }
+        },
+        "$ref" : "#/definitions/getDataDef"
+    }
+    
+    /** public functions - interface for parent */
+    
+    this.setSelectionToControl = function(p_selection) {
+        v_selections.push(p_selection);
+    };
+    
+    this.setReponseDataPath = function(p_index, p_path) {
+        v_dataPaths[p_index] = p_path;
+    };
+    
+    this.setBinder = function(p_binder) {
+        v_binder = p_binder;
+    };
+	
+	/** public functions - interface for views */ 
+    
+    this.setJSONData = function(p_data) {
+        if (v_request != undefined) {
+            for (var id in p_data) {
+                v_request[id] = p_data[id];
+            }
+        }
+    }
+    
+    this.getJSONData = function(callback) {
+        v_request = v_viewmodel.getRequestFromPath(v_dataPaths[0]);
+        callback(v_request);
+    };
+    
+    this.getSchema = function() {
+        return v_schema;
+    }
+}
+
+CViewModel_RequestManipulator.getHelp = function() {
+    return "A viewmodel that can be connected to a JSON editor to edit the connected request.";
+};
+
+CViewModel_RequestManipulator.providesInterface = function() {
+    return ["getSchema", "setJSONData", "getJSONData"];
+};
+
+CViewModel_RequestManipulator.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_RequestManipulator",
+        "type": "object",
+        "properties": {},
+        "additionalProperties": false
+    };
+};
+
+CViewModel_RequestManipulator.expectsConnection = function() {
+    return {
+        "dataConnections": [{}],
+        "selectionConnections": []
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_RequestManipulator.js
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_RequestToggle.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_RequestToggle.js
new file mode 100644
index 0000000..b88f97b
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_RequestToggle.js
@@ -0,0 +1,123 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_RequestToggle(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    
+    var v_binder;
+    var v_dataPaths = [];
+    var v_selections = [];
+    
+    var v_selected = 0;
+    var v_defaultFilter;
+    
+    var v_filters = [];
+    
+    /** public functions - interface for parent */
+    
+    this.setSelectionToControl = function(p_selection) {
+        v_selections.push(p_selection);
+    };
+    
+    this.setReponseDataPath = function(p_index, p_path) {
+        v_dataPaths[p_index] = p_path;
+        var request = v_viewmodel.getRequestFromPath(p_path);
+        v_filters[p_index] = request.getData.filter;
+        if (v_options.toggleGroups[1] != undefined && p_index >= v_options.toggleGroups[1]) {
+            request.getData.filter = {"dataValue": "false"};
+        }
+    };
+    
+    this.setBinder = function(p_binder) {
+        v_binder = p_binder;
+    };
+	
+	/** public functions - interface for views */ 
+    
+    this.select = function(groupIndex) {
+        v_selected = groupIndex;
+        
+        var firstDataPathIndex = v_options.toggleGroups[groupIndex];
+        var lastDataPathIndex = v_options.toggleGroups[groupIndex + 1];
+        if (lastDataPathIndex == undefined) {
+            lastDataPathIndex = v_dataPaths.length;
+        }
+        
+        for (var i = 0; i < firstDataPathIndex; ++i) {
+            setFilter(i, false);
+        }
+        
+        for (var i = firstDataPathIndex; i < lastDataPathIndex; ++i) {
+            setFilter(i, true);
+        }
+        
+        for (var i = lastDataPathIndex; i < v_dataPaths.length; ++i) {
+            setFilter(i, false);
+        }
+        
+        v_binder.notifyChange(true);
+    };
+    
+    this.getList = function() {
+        return {"selections": [v_selected]};
+    };
+    
+    /** private functions */
+    
+    function setFilter(dataPathIndex, setOriginal) {
+        var request = v_viewmodel.getRequestFromPath(v_dataPaths[dataPathIndex]);
+        if (request != undefined) {
+            if (setOriginal) {
+                request.getData.filter = v_filters[dataPathIndex];
+            } else {
+                request.getData.filter = {"dataValue": "false"};
+            }
+        }
+    }
+}
+
+CViewModel_RequestToggle.getHelp = function() {
+    return "This viewmodel can be used to toggle the filter of the connected request groups between their original filters and a constant false filter.";
+}
+
+CViewModel_RequestToggle.providesInterface = function() {
+    return ["select", "getList"];
+};
+
+CViewModel_RequestToggle.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_RequestToggle",
+        "type": "object",
+        "properties": {
+            "toggleGroups": {
+                "description": "The index of the first element in each group.",
+                "type": "array",
+                "format": "table",
+                "items": {
+                    "title": "group",
+                    "type": "integer",
+                    "min": 0,
+                    "uniqueItems": true,
+                    "minItems": 1
+                }
+            },
+            "filterIndex": {
+                "type": "integer",
+                "description": "The data path index whose filter will be used as default.",
+                "default": 0
+            }
+        },
+        "additionalProperties": false,
+        "required": ["toggleGroups"]
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_RequestToggle.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_ResponseMerger.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_ResponseMerger.js
new file mode 100644
index 0000000..a25a2d2
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_ResponseMerger.js
@@ -0,0 +1,147 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_ResponseMerger(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    
+    var v_binder;
+    var v_dataPaths = [];
+    var v_selections = [];
+    
+    var v_rowData = [];
+    var v_selected = 0;
+    
+    /** public functions - interface for parent */
+    
+    this.setSelectionToControl = function(p_selection) {
+        v_selections.push(p_selection);
+    };
+    
+    this.setReponseDataPath = function(p_index, p_path) {
+        v_dataPaths[p_index] = p_path;
+    };
+    
+    this.setBinder = function(p_binder) {
+        v_binder = p_binder;
+    };
+	
+    /** public functions - interface for views */ 
+    
+    this.getList = function() {
+        v_rowData = [];
+        var counter = 0;
+        var newList = [[]];
+        for (var i = 0; i < v_dataPaths.length; ++i) {
+            var response = v_viewmodel.getResponseElement(v_dataPaths[i]);
+            if (response != undefined) {
+                v_rowData.push({"rowIndex": counter, "isNode": response.node != undefined});
+                if (response.node != undefined) {
+                    ++counter;
+                    newList[0].push(getNodeLabel(response.node, i));
+                } else if (response.list != undefined) {
+                    for (var j = 0; j < response.list.length; ++j) {
+                        ++counter;
+                        newList[0].push([response.list[j].node.val, [], response.list[j].node.tp > 0]);
+                    }
+                }
+            } else {
+                v_rowData.push({"rowIndex": counter, "isNode": true});
+            }
+        }
+        
+        return {
+            "values": newList,
+            "selections": [[v_selected]]
+        }
+    };
+    
+    this.select = function(p_index) {
+        var connection = 0;
+        var index = 0;
+        for (var i = v_rowData.length - 1; i >= 0; --i) {
+            if (p_index >= v_rowData[i].rowIndex) {
+                connection = i;
+                index = p_index - v_rowData[i].rowIndex;
+                break;
+            }
+        }
+        
+        for (var i = 0; i < v_selections.length; ++i) {
+            if (v_rowData[i] == undefined || v_rowData[i].isNode) {
+                v_selections[i].filter = {"dataValue": "false"};
+            } else {
+                v_selections[i].selection = [];
+            }
+        }
+        
+        if (v_rowData[connection] == undefined || v_rowData[connection].isNode) {
+            v_selections[connection].filter = {"dataValue": "true"};
+        } else {
+            v_selections[connection].selection = [index];
+        }
+        
+        v_selected = p_index;
+        v_binder.notifyChange(true);
+    };
+    
+    function getNodeLabel(node, index) {
+        if (v_options.predefinedValues != undefined) {
+            for (var i = 0; i < v_options.predefinedValues.length; ++i) {
+                if (v_options.predefinedValues[i].dataPathIndex == index) {
+                    return [v_options.predefinedValues[i].value, [], node.tp > 0];
+                }
+            }
+        }
+        return [node.val, [], node.tp > 0];
+    }
+}
+
+CViewModel_ResponseMerger.getHelp = function() {
+    return "The viewmodel will create a single list form all its data connections.\n" +
+        "When selecting an element, the request will be modified:\n" +
+            "\tif the element returns a single node, a false filter will be added\n" +
+            "\tif the element returns a list, its selection will be modified" +
+        "It will not work if the selection connections are different than the data connections or there are other filters on the connected requests.";
+};
+
+CViewModel_ResponseMerger.providesInterface = function() {
+    return ["getList", "select"];
+};
+
+CViewModel_ResponseMerger.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_ResponseMerger",
+        "type": "object",
+        "properties": {
+            "predefinedValues": {
+                "description": "The predefined values for the non-iterator elements (WARNING: do not use with iterators).",
+                "type": "array",
+                "format": "table",
+                "items": {
+                    "type": "object",
+                    "properties": {
+                        "dataPathIndex": {
+                            "type": "integer"
+                        },
+                        "value": {
+                            "type": "string"
+                        }
+                    },
+                    "required": ["dataPathIndex", "value"],
+                    "additionalProperties": false
+                }
+            }
+        },
+        "additionalProperties": false
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\CViewModel_ResponseMerger.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_SetupLoaderBasedOnCondition.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_SetupLoaderBasedOnCondition.js
new file mode 100644
index 0000000..b210e01
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_SetupLoaderBasedOnCondition.js
@@ -0,0 +1,58 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_SetupLoaderBasedOnCondition(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var base = new CViewModel_Condition(p_viewmodel, p_options);
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    
+    var v_dataPaths = [];
+    
+    /** public functions - interface for parent */
+    
+    this.setSelectionToControl = base.setSelectionToControl;
+    this.setReponseDataPath = base.setReponseDataPath;
+    this.setBinder = base.setBinder;
+	
+    /** private functions - interface for views */ 
+    
+    function loadSetup() {
+        if (v_viewmodel.isRunning()) {
+            var value = base.getState();
+            if (value) {
+                clearInterval(timer);
+                v_viewmodel.loadSetup(v_options.setupToLoad, undefined, true);
+            }
+        } else {
+            clearInterval(timer);
+        }
+    };
+    
+    var timer = setInterval(loadSetup, 50);
+}
+
+CViewModel_SetupLoaderBasedOnCondition.getHelp = function() {
+    return "A viewmodel that loads a setup given in its custom data when a condition is met.";
+}
+
+CViewModel_SetupLoaderBasedOnCondition.providesInterface = function() {
+    return [];
+};
+
+CViewModel_SetupLoaderBasedOnCondition.getCustomDataSchema = function() {
+    var schema = CViewModel_Condition.getCustomDataSchema();
+    schema.properties.setupToLoad = {
+        "description": "The name of the setup to load",
+        "type": "string"
+    };
+    schema.required = ["setupToLoad"];
+    return schema;
+};
+
+//# sourceURL=CustomizableApp\ViewModels\CViewModel_SetupLoaderBasedOnCondition.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_SetupTabs.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_SetupTabs.js
new file mode 100644
index 0000000..ff0b802
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_SetupTabs.js
@@ -0,0 +1,306 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_SetupTabs(a_viewmodel, a_options) {
+    "use strict";
+    
+    /** constructor */
+    
+    var m_Binder;
+    var m_options = a_options;
+    var m_setupModel = a_viewmodel.getSetupModel();
+    var m_setupList = a_viewmodel.getSetupList();
+    var m_hierarchy = m_options.hierarchy;
+    var m_parentViewmodel = a_viewmodel;
+    var m_conditionViewmodels = [];
+    var m_setupName = m_setupModel.getSetup().name;
+    var m_setupParams = m_setupModel.getSetup().setupParams;
+    
+    function insertMissingSetups() {
+        var otherOrganizer = {"displayName": "other", "type": "organizer", "menuElements": []};
+        var setupsInHierarchy = [];
+        findAllSetupsInHierarchy(setupsInHierarchy, m_hierarchy.menuElements);
+        for (var i = 0; i < m_setupList.length; ++i) {
+            if (setupsInHierarchy.indexOf(m_setupList[i]) == -1)
+                otherOrganizer.menuElements.push({"setupName": m_setupList[i], "type": "setup"});
+        }
+        if (otherOrganizer.menuElements.length > 0)
+            m_hierarchy.menuElements.push(otherOrganizer);
+    }
+    
+    function findAllSetupsInHierarchy(aFoundSetups, aMenuElements) {
+        for (var i = 0; i < aMenuElements.length; ++i) {
+            if (aMenuElements[i].setupName != undefined) {
+                aFoundSetups.push(aMenuElements[i].setupName);
+            }
+            if (aMenuElements[i].menuElements != undefined) {
+                findAllSetupsInHierarchy(aFoundSetups, aMenuElements[i].menuElements);
+            }
+        }
+    }
+    
+    if (m_options.displayOtherSetups)
+        insertMissingSetups();
+    
+    var m_this = this;
+    
+    /** public functions - interface for parent */
+    
+    this.setBinder = function(aBinder)
+    {
+        m_Binder = aBinder;
+    };
+    
+    this.setReponseDataPath = function(aIndex, aPath) {
+        m_conditionViewmodels[aIndex] = new CViewModel_Condition(m_parentViewmodel, {});
+        m_conditionViewmodels[aIndex].setReponseDataPath(0, aPath);
+    };
+    
+    /** public functions - interface for views */
+    
+    this.getRecursiveSetups = function(callback)
+    {
+        return new CViewmodel_RecursiveSetups(m_this, m_hierarchy.menuElements, m_this.getFullNameOfSetup(m_setupName, m_setupParams), []);
+    };
+    
+    /** public functions - interface for subviewmodels */
+    
+    this.select = function(a_setup, a_setupParams)
+    {
+        m_parentViewmodel.loadSetup(a_setup, a_setupParams);
+    };
+    
+    this.checkVisibility = function(dataPathIndex) {
+        if (m_conditionViewmodels[dataPathIndex] != undefined) {
+            return m_conditionViewmodels[dataPathIndex].getState();
+        } else {
+            return true;
+        }
+    };
+    
+    this.getFullNameOfSetup = function(setupName, setupParams) {
+        var name = setupName;
+        if (setupParams != undefined) {
+            name += "_" + JSON.stringify(setupParams);
+        }
+        return name;
+    };
+};
+
+function CViewmodel_RecursiveSetups(a_parentViewmodel, a_menuElements, a_selectedSetupName, a_organizerNames) {
+    "use strict";
+    var m_setupList = [];
+    var m_setupNameList = [];
+    var m_setupParamsList = [];
+    var m_menuElements = a_menuElements;
+    var m_selectedIndex = 0;
+    var m_subViewModels = [];
+    var m_parentViewmodel = a_parentViewmodel;
+    var m_selectedSetupName = a_selectedSetupName;
+    var m_organizerNames = a_organizerNames;
+    var m_this = this;
+    
+    var counter = 0;
+    var selectedElementIsFound = false;
+    for (var i = 0; i < m_menuElements.length; ++i) {
+        if (m_menuElements[i].isVisible == undefined || m_parentViewmodel.checkVisibility(m_menuElements[i].isVisible)) {
+            if (m_selectedSetupName != undefined && m_menuElements[i] && m_selectedSetupName == m_parentViewmodel.getFullNameOfSetup(m_menuElements[i].setupName, m_menuElements[i].setupParams)) {
+                m_selectedIndex = counter;
+                localStorage.setItem(getKey(), counter);
+                selectedElementIsFound = true;
+                break;
+            }
+            ++counter;
+        }
+    }
+        
+    counter = 0;
+    for (var i = 0; i < m_menuElements.length; ++i) 
+    {
+        if (m_menuElements[i].isVisible == undefined || m_parentViewmodel.checkVisibility(m_menuElements[i].isVisible)) {
+            if (m_menuElements[i].displayName)
+                m_setupList[counter] = [m_menuElements[i].displayName];
+            else
+                m_setupList[counter] = [m_menuElements[i].setupName];
+            m_setupNameList[counter] = m_menuElements[i].setupName;
+            m_setupParamsList[counter] = m_menuElements[i].setupParams;
+            var setupToSelect;
+            if (!selectedElementIsFound)
+                setupToSelect = m_selectedSetupName;
+            if (m_menuElements[i].menuElements && m_menuElements[i].menuElements.length) {
+                var organizerPath = mcopy(m_organizerNames);
+                organizerPath.push(m_menuElements[i].displayName);
+                m_subViewModels[counter] = new CViewmodel_RecursiveSetups(m_parentViewmodel, m_menuElements[i].menuElements, setupToSelect, organizerPath);
+                if (m_subViewModels[counter].isSelectedElementFound()) {
+                    m_selectedIndex = counter;
+                    localStorage.setItem(getKey(), counter);
+                    selectedElementIsFound = true;
+                }
+            }
+            
+            ++counter;
+        }
+    }
+    
+    this.getSubViewModels = function()
+    {
+        return m_subViewModels;
+    };
+    
+    this.getselectedSetup = function()
+    {
+        var selectedIndex = localStorage.getItem(getKey());
+        if (selectedIndex == undefined || selectedIndex >= m_setupNameList.length) {
+            selectedIndex = m_selectedIndex;
+        }
+        
+        var selectedSetupName;
+        if (!m_subViewModels[selectedIndex])
+           return [m_setupNameList[selectedIndex], m_setupParamsList[selectedIndex]];
+        else
+           return m_subViewModels[selectedIndex].getselectedSetup();
+    };
+
+    this.getList = function()
+    {
+        return {
+            selections: [[m_selectedIndex]],
+            values: [m_setupList]
+        };
+    };
+    
+    this.select = function(a_Index)
+    {
+        m_selectedIndex = a_Index;
+        localStorage.setItem(getKey(), m_selectedIndex);
+        var selected = m_this.getselectedSetup();
+        m_parentViewmodel.select(selected[0], selected[1]);
+    };
+    
+    this.isSelectedElementFound = function() {
+        return selectedElementIsFound;
+    };
+    
+    function getKey() {
+        var key = "setupTabSelection";
+        for (var i = 0; i < m_organizerNames.length; ++i) {
+            key += "_" + m_organizerNames[i];
+        }
+        return key;
+    }
+}
+
+CViewModel_SetupTabs.getHelp = function() {
+    return "A viewmodel that contains the setup hierarchy.";
+};
+
+CViewModel_SetupTabs.providesInterface = function() {
+    return ["getRecursiveSetups"];
+};
+
+CViewModel_SetupTabs.getCustomDataSchema = function() {
+    return {
+        "$schema" : "http://json-schema.org/draft-04/schema#",
+        "definitions": {
+            "setup": {
+                "title": "Setup",
+                "description": "defines a setup",
+                "type": "object",
+                "additionalProperties": false,
+                "properties": {
+                    "displayName": {
+                        "title": "display name",
+                        "description": "the name that is displayed",
+                        "type": "string"
+                    },
+                    "setupName": {
+                        "title": "setup name",
+                        "description": "the name of the setup",
+                        "type": "string"
+                    },
+                    "type": {
+                        "type": "string",
+                        "enum": ["setup"]
+                    },
+                    "isVisible": {
+                        "type": "integer",
+                        "description": "the data path index of a connected request that returns a bool value or contains a filter"
+                    },
+                    "setupParams": {
+                        "type": "object",
+                        "additionalProperties": true,
+                        "properties": {}
+                    }
+                },
+                "required": ["setupName", "type"]
+            },
+            "organizer": {
+                "title": "Organizer",
+                "description": "defines an organizer which can contain additional organizers and setups",
+                "type": "object",
+                "additionalProperties": false,
+                "properties": {
+                    "displayName": {
+                        "title": "display name",
+                        "description": "the name that is displayed",
+                        "type": "string"
+                    },
+                    "type": {
+                        "type": "string",
+                        "enum": ["organizer"]
+                    },
+                    "menuElements": {
+                        "$ref" : "#/definitions/menuElements"
+                    },
+                    "isVisible": {
+                        "type": "integer",
+                        "description": "the data path index of a connected request that returns a bool value or contains a filter"
+                    }
+                },
+                "required" : ["displayName", "type"]
+            },
+            "menuElements": {
+                "title": "Menu elements",
+                "description": "the list of menu elements",
+                "type": "array",
+                "format": "tabs",
+                "items": {
+                    "title": "menu element",
+                    "oneOf" : [
+                        {
+                            "$ref" : "#/definitions/organizer"
+                        },
+                        {
+                            "$ref" : "#/definitions/setup"
+                        }
+                    ]
+                }
+            }
+        },
+        "title": "Setup hierarchy",
+        "type" : "object",
+        "additionalProperties" : false,
+        "properties" : {
+            "hierarchy": {
+                "description": "The setup hierarchy.",
+                "type": "object",
+                "properties": {
+                    "menuElements" : {
+                        "$ref" : "#/definitions/menuElements"
+                    }
+                },
+                "additionalProperties" : false
+            },
+            "displayOtherSetups": {
+                "description": "Whether we want to display the other setups not included in the hierarchy.",
+                "type": "boolean",
+                "format": "checkbox",
+                "default": true
+            }
+        }
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_SetupTabs.js
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_TableForLargeData.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_TableForLargeData.js
new file mode 100644
index 0000000..55f76b9
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_TableForLargeData.js
@@ -0,0 +1,183 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_TableForLargeData(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    
+    var v_binder;
+    var v_dataPaths = [];
+    var v_selections = [];
+    
+    var v_streamingThreshold = 50;
+    if (v_options.streamingThreshold != undefined) {
+        v_streamingThreshold = v_options.streamingThreshold;
+    }
+    
+    var v_rangeFilterCount = v_streamingThreshold;
+    if (v_options.rangeFilterCount != undefined) {
+        v_rangeFilterCount = v_options.rangeFilterCount;
+    }
+    
+    var v_wasStreaming = false;
+    
+    var base = new CViewModel_DynamicTable(p_viewmodel, p_options);
+    var paging = new CViewModel_Paging(p_viewmodel, p_options);
+    
+    /** public functions - interface for parent */ 
+    
+    this.setSelectionToControl = function(p_selection) {
+        base.setSelectionToControl(p_selection);
+        v_selections.push(p_selection);
+    };
+    
+    this.setReponseDataPath = function(p_index, p_path) {
+        if (p_index == 0) {
+            paging.setReponseDataPath(p_index, p_path);
+        } else if (p_index == 1) {
+            paging.setReponseDataPath(p_index, p_path);
+            base.setReponseDataPath(p_index - 1, p_path);
+            v_dataPaths[0] = p_path;
+        } else {
+            base.setReponseDataPath(p_index - 1, p_path);
+        }
+    };
+    
+    this.setBinder = function(p_binder) {
+        base.setBinder(p_binder);
+        paging.setBinder(p_binder);
+        v_binder = p_binder;
+    };
+    
+    /** public functions - interface for views */
+	
+    this.select = function(p_index) {
+        for (var i = 0; i < v_selections.length; ++i) {
+            var responseElement = v_viewmodel.getResponseElement(v_dataPaths[0]);
+            if (responseElement != undefined && responseElement.list[p_index] != undefined) {
+                v_viewmodel.selectByValue(v_selections[i], responseElement.list[p_index].node.val, p_index);
+            } else {
+                v_viewmodel.select(v_selections[i], p_index);
+            }
+        }
+        if (v_selections.length > 0) {
+            v_binder.notifyChange(true);
+        }
+    };
+    this.getHeader = base.getHeader;
+    this.getName = base.getName;
+    this.getTable = base.getTable;
+    this.setValue = base.setValue;
+    
+    this.getRange = function() {
+        var size = paging.getSize();
+        var max = size;
+        if (v_options.allowScrollBelow == false) {
+            max = max - paging.getRangeFilter().count + 1;
+        }
+        return {
+            "min": 0,
+            "max": max
+        };
+    };
+    
+    this.getPosition = function() {
+        return paging.getRangeFilter().offset;
+    };
+    
+    this.setPosition = function(position) {
+        return paging.changeFilter({"offset": {"to": position}});
+    };
+    
+    this.getViewportSize = function() {
+        return paging.getRangeFilter().count;
+    };
+    
+    this.isStreaming = function() {
+        var size = paging.getSize();
+        var isStreaming = size > v_streamingThreshold;
+        
+        if (isStreaming && !v_wasStreaming) {
+            var request = v_viewmodel.getRequestFromPath(v_dataPaths[0]);
+            request.getData.rangeFilter.count = v_rangeFilterCount;
+        } else if (v_wasStreaming && !isStreaming) {
+            var request = v_viewmodel.getRequestFromPath(v_dataPaths[0]);
+            request.getData.rangeFilter.count = v_streamingThreshold;
+        }
+        
+        v_wasStreaming = isStreaming;
+        return isStreaming;
+    };
+}
+
+CViewModel_TableForLargeData.getHelp = function() {
+    return "A table viewmodel that can handle large amounts of data.\n" + 
+        "The second data connection must be a list which defines the rows of the table. The first data connection must be its size.\n" + 
+        "If more connections are given, they will represent the columns of the table.";
+};
+
+CViewModel_TableForLargeData.providesInterface = function() {
+    return ["select", "getName", "getHeader", "getTable", "setValue", "getRange", "getPosition", "setPosition", "getViewportSize", "isStreaming"];
+};
+
+CViewModel_TableForLargeData.getCustomDataSchema = function() {
+    var schema = CViewModel_DynamicTable.getCustomDataSchema();
+    var pagingSchema = CViewModel_Paging.getCustomDataSchema();
+    for (var id in pagingSchema.properties) {
+        schema.properties[id] = pagingSchema.properties[id];
+    }
+    
+    schema.title = "Custom data for CViewModel_TableForLargeData";
+    schema.properties.streamingThreshold = {
+        "description": "If the list is longer than this amount, use range filter to reduce the number of elements returned.",
+        "type": "integer",
+        "min": 1,
+        "default": 50
+    };
+    schema.properties.rangeFilterCount = {
+        "description": "When using range filter, this many elements will be returned.",
+        "type": "integer",
+        "min": 1,
+        "default": 20
+    };
+    return schema;
+};
+
+CViewModel_TableForLargeData.expectsConnection = function() {
+    var dataConnections = [
+        {
+            "source": "DataSource",
+            "element": "sizeOf"
+        },
+        {
+            "valueType": ["charstringlistType", "integerlistType", "floatlistType"]
+        },
+        {
+            "childOfDataConnection": 1,
+            "valueType": ["charstringType", "intType", "floatType", "statusLEDType", "boolType"],
+            "multiple": true,
+            "optional": true
+        }
+    ];
+    
+    var selectionConnections = [
+        {
+            "dataElementOfDataConnection": 1,
+            "multiple": true,
+            "optional": true
+        }
+    ];
+    
+    return {
+        "dataConnections": dataConnections,
+        "selectionConnections": selectionConnections
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_TableForLargeData.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_UnionTable.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_UnionTable.js
new file mode 100644
index 0000000..9a856ef
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_UnionTable.js
@@ -0,0 +1,201 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_UnionTable(aViewModel, aOptions) {

+    "use strict";

+

+    /** private members */

+    var mViewModel = aViewModel;

+    var mOptions = aOptions;

+    //var mRq = mViewModel.getRequest();

+    var mBinder;

+    var mReponseDataPaths = [];

+    var mSelections = []; // mSelectionss is a list of references to objects, each containing a field named "selection"

+    var mThis = this;

+    var mEnlistElementName = mOptions.enlistElementName;

+    if (mEnlistElementName === undefined)

+        mEnlistElementName = true;

+

+    /** public functions - Interface for parent */

+

+    this.setSelectionToControl = function (aSelection) {

+        /** aSelection is a reference to an object containing a "selection" field */

+        mSelections.push(aSelection);

+    };

+

+    this.setReponseDataPath = function (aExpectedReponseDataIndex, aReponseDataPath) {

+        mReponseDataPaths[aExpectedReponseDataIndex] = aReponseDataPath;

+    };

+

+    this.setBinder = function (aBinder) {

+        mBinder = aBinder;

+    };

+

+    /** public functions - Interface for views */

+    this.select = function (aIndex) {

+        for (var i = 0; i < mSelections.length; ++i)

+            mViewModel.select(mSelections[i], aIndex);

+        mBinder.notifyChange();

+    };

+

+    this.getHeader = function () {

+        var header = [];

+        if (mOptions.header) {

+            header = mcopy(mOptions.header);

+        } else {

+            var request = (mViewModel.getRequestFromPath())[mReponseDataPaths[0][0]];

+            if (mEnlistElementName) {

+                for(var i = 1; i < mReponseDataPaths[0].length; i++) { //for parents

+                   header.push(request.getData.element);

+                   request = request.getData.children[mReponseDataPaths[0][i]];

+                }

+                header.push(request.getData.element); //for connected node (data connection)

+            }

+            if (request.getData.children) { // for children

+                for (var i = 0; i < request.getData.children.length; ++i) {

+                    header.push(request.getData.children[i].getData.element);

+                }

+            }

+        }

+        

+        for (var i = 0; i < header.length; ++i) {

+            header[i] = {

+                "heading": header[i],

+                "elementIndex": i

+            };

+        }

+        return header;

+    };

+

+    this.getName = function () {

+        return mViewModel.getRequestFromPath(mReponseDataPaths[0]).getData.element;

+    };

+

+    this.getResponseElement = function (aReponseDataPath, aFullTableSelection) {

+        var lElement;

+        if (aFullTableSelection) {

+            aFullTableSelection.parents = [];

+            aFullTableSelection.depth = aReponseDataPath.length;

+            aFullTableSelection.path = aReponseDataPath;

+        }

+        if (aReponseDataPath) {

+            lElement = mViewModel.getResponseElement();

+            if (lElement != undefined) {

+                lElement = lElement[aReponseDataPath[0]];

+            }

+            if (lElement) {

+                var lRq = mViewModel.getRequest()[aReponseDataPath[0]];

+                for (var i = 1; i < aReponseDataPath.length && lElement; ++i) {

+                    if (lElement.list && lRq.getData.selection && lRq.getData.selection.length > 0) {

+                        if (aFullTableSelection) {

+                            aFullTableSelection.depth--;

+                            if (lElement.list[lRq.getData.selection[0]] != undefined) {

+                                aFullTableSelection.parents.push(lElement.list[lRq.getData.selection[0]].node.val);

+                            } else {

+                                aFullTableSelection.parents.push(undefined);

+                            }

+                            aFullTableSelection.path = aFullTableSelection.path.slice(1);

+                        }

+                        if (lElement.list[lRq.getData.selection[0]] && lElement.list[lRq.getData.selection[0]].node.childVals) {

+                            lElement = lElement.list[lRq.getData.selection[0]].node.childVals[aReponseDataPath[i]];

+                        } else {

+                            lElement = undefined;

+                            break;

+                        }

+                    } else if (!lRq.getData.selection || lRq.getData.selection.length === 0) {

+                        /**/

+                    } else if (lElement.node && lElement.node.childVals) {

+                        lElement = lElement.node.childVals[aReponseDataPath[i]];

+                    } else

+                        lElement = {

+                            "error" : "cannot determine node"

+                        };

+                    if (lRq.getData.children)

+                        lRq = lRq.getData.children[aReponseDataPath[i]];

+                }

+            }

+        }

+        return lElement;

+    };

+

+    this.getTable = function () {

+        var aFullTableSelection = {};

+        var response = mThis.getResponseElement(mReponseDataPaths[0], aFullTableSelection);

+        return {

+            selection : mSelections[0] ? mSelections[0].selection : undefined,

+            table :  (response === undefined) ? [] : flattenResponseElement(response.list, aFullTableSelection.depth, 0, aFullTableSelection.parents, aFullTableSelection.path.slice(1))

+        };

+    };

+    

+    this.setValue = function() {};

+

+    /** private functions */

+

+    function flattenResponseElement(arr, limit, depth, parents, path) {

+        if (arr) {

+        limit = limit || 0;

+        depth = depth || 0;

+        parents = parents || [];

+        path = path || [];

+        return arr.reduce(function _reduce(flat, toFlatten) {

+            if (limit === depth && toFlatten.node)

+                return flat.concat({"val": toFlatten.node.val});

+            else if (limit === depth && toFlatten.list)

+                return flat.concat([flattenResponseElement(toFlatten.list, limit, depth, parents, path)].join());

+            else if (limit === depth + 1 && toFlatten.node) {

+                if (mEnlistElementName)

+                    return flat.concat([parents.concat([{"val": toFlatten.node.val}].concat(flattenResponseElement(toFlatten.node.childVals, limit, depth + 1, [], path)))]);

+                else

+                    return flat.concat([flattenResponseElement(toFlatten.node.childVals, limit, depth + 1, [], path)]);

+            } else if (Array.isArray(toFlatten))

+                return flat.concat(flattenResponseElement(toFlatten, limit, depth, parents, path));

+            else if (toFlatten.node && toFlatten.node.childVals && limit !== depth)

+                return flat.concat(flattenResponseElement([toFlatten.node.childVals[path[depth]]], limit, depth + 1, parents.concat([{"val": toFlatten.node.val}]), path));

+            else if (toFlatten.node && toFlatten.node.childVals)

+                return flat.concat(flattenResponseElement(toFlatten.node.childVals, limit, depth + 1, parents.concat([{"val": toFlatten.node.val}]), path));

+            else if (toFlatten.list)

+                return flat.concat(flattenResponseElement(toFlatten.list, limit, depth, parents, path));

+            else

+                console.error("flattenResponseElement met an unexpected condition. Reason: The response object is nonconformant OR not all parents have a selection!");

+        }, []);

+        }

+    }

+}

+

+CViewModel_UnionTable.getHelp = function() {

+    return "A viewmodel that creates a merged table when there are iterators above the normal table-like request structure.\n" +

+        "The select and setValue methods are not implemented.";

+}

+

+CViewModel_UnionTable.providesInterface = function () {

+    return ["select", "getName", "getHeader", "getTable", "setValue"];

+};

+

+CViewModel_UnionTable.getCustomDataSchema = function () {

+    return {

+        "$schema" : "http://json-schema.org/draft-04/schema#",

+        "title" : "Custom data for CViewModel_UnionTable",

+        "type" : "object",

+        "properties" : {

+            "header": {

+                "description": "The header of the table. It should have as many elements as the number of columns.",

+                "type": "array",

+                "format": "table",

+                "items": {

+                    "type": "string",

+                    "title": "heading"

+                }

+            },

+            "enlistElementName": {

+                "description": "Whether we add the parents to the table.",

+                "type": "boolean",

+                "format": "checkbox",

+                "default": false

+            }

+        }

+    };

+};

+

+//# sourceURL=CustomizableApp\ViewModels\ViewModel_UnionTable.js

diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_WritableCondition.js b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_WritableCondition.js
new file mode 100644
index 0000000..3075454
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/ViewModel_WritableCondition.js
@@ -0,0 +1,27 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_WritableCondition(p_viewmodel, p_options) {
+    "use strict";
+
+    var base = new CViewModel_Condition(p_viewmodel, p_options);
+    base.isWritable = base.getState;
+    base.getState = undefined;
+    return base;
+}
+
+CViewModel_WritableCondition.getHelp = function() {
+    return "This viewmodel is the same as the condition viewmodel, but its interface is called differently.";
+}
+
+CViewModel_WritableCondition.providesInterface = function() {
+    return ["isWritable"];
+};
+
+CViewModel_WritableCondition.getCustomDataSchema = function() {
+    return CViewModel_Condition.getCustomDataSchema();
+};
+
+//# sourceURL=CustomizableApp\ViewModels\CViewModel_WritableCondition.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/Viewmodel_FilterAndSort.js b/htdocs/WebApplications/CustomizableApp/ViewModels/Viewmodel_FilterAndSort.js
new file mode 100644
index 0000000..f617a23
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/Viewmodel_FilterAndSort.js
@@ -0,0 +1,240 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_FilterAndSort(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    var v_binder;
+    
+    var v_currentIndexes = [];
+    var v_currentSorting = v_options.initialSorting;
+    var v_currentFilter = v_options.initialFilter;
+    
+    /** public functions - interface for parent */ 
+    
+    this.setBinder = function(p_binder) {
+        v_binder = p_binder;
+    };
+	
+	/** public functions - interface for views */ 
+    
+    this.setFilter = function(p_filter) {
+        v_currentFilter = p_filter;
+    };
+    
+    this.getFilter = function() {
+        return v_currentFilter;
+    };
+    
+    this.setSort = function(p_sort) {
+        v_currentSorting = p_sort;
+    };
+    
+    this.getSort = function() {
+        return v_currentSorting;
+    };
+    
+    this.getAlteredData = function(p_data) {
+        // only table for now...
+        v_currentIndexes = [];
+        for (var i = 0; i < p_data.table.length; ++i) {
+            v_currentIndexes.push(i);
+        }
+        if (v_options.filter !== false) {
+            filter(p_data.table);
+        }
+        if (v_options.sort !== false) {
+            sort(p_data.table);
+        }
+        if (p_data.selection != undefined) {
+            p_data.selection = updateSelection(mcopy(p_data.selection));
+        }
+        
+        return p_data;
+    };
+    
+    this.getUnalteredIndex = function(p_index) {
+        if (v_currentIndexes.length != 0) {
+            return v_currentIndexes[p_index];
+        } else {
+            return p_index;
+        }
+    };
+    
+    /** private functions */
+    
+    function filter(data) {
+        if (v_currentFilter != undefined && v_currentFilter != "") {
+            var regexps = [];
+            var strings = v_currentFilter.split(" ");
+            for (var i = 0; i < strings.length; ++i) {
+                regexps.push(new RegExp(strings[i], "gi"));
+            }
+            
+            var index = 0;
+            var currentIndex = 0;
+            while (index < data.length) {
+                if (!matchesAll(data[index], regexps)) {
+                    data.splice(index, 1);
+                    v_currentIndexes.splice(index, 1);
+                } else {
+                    ++index;
+                }
+                ++currentIndex;
+            }
+        }
+    }
+    
+    function matchesAll(obj, regexps) {
+        var isAMatch = true;
+        for (var i = 0; i < regexps.length && isAMatch; ++i) {
+            isAMatch = isAMatch && matches(obj, regexps[i]);
+        }
+        return isAMatch;
+    }
+    
+    function matches(obj, regexp) {
+        // TODO this will not work with element relay's getListWithElementInfo()
+        var isAMatch = false;
+        for (var i = 0; i < obj.length && !isAMatch; ++i) {
+            if ($.type(obj[i].val) === "string" && obj[i].val.match(regexp) != null) {
+                isAMatch = true;
+            } else if ($.type(obj[i].val) === "array") {
+                isAMatch = matches(obj[i].val, regexp);
+            }
+        }
+        return isAMatch;
+    }
+    
+    function sort(data) {
+        var insertTo = 0;
+        var dataLength = data.length;
+        for (var i = 0; i < dataLength; ++i) {
+            var min = findNext(data, insertTo);
+            changeOrder(data, insertTo, min);
+            ++insertTo;
+        }
+    }
+    
+    function findNext(data, p_from) {
+        var index = p_from;
+        for (var i = p_from + 1; i < data.length; ++i) {
+            if (checkSort(data[i], data[index])) {
+                index = i;
+            }
+        }
+        return index;
+    }
+    
+    function checkSort(obj1, obj2) {
+        if (v_currentSorting != undefined) {
+            var index = v_currentSorting.sortBy;
+            var method = v_currentSorting.sortDirection;
+            // TODO index is not correct when obj[1] contains the children and is > 0
+            // It will also not work with element relay's getListWithElementInfo()
+            if ((method == "asc" && obj1[index].val < obj2[index].val) || (method == "desc" && obj1[index].val > obj2[index].val)) {
+                return true;
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+    
+    function changeOrder(data, insertTo, min) {
+        if (insertTo != min) {
+            var obj = data[min];
+            var index = v_currentIndexes[min];
+            data[min] = data[insertTo];
+            v_currentIndexes[min] = v_currentIndexes[insertTo];
+            data[insertTo] = obj;
+            v_currentIndexes[insertTo] = index;
+        }
+    }
+    
+    function updateSelection(selection) {
+        if (v_currentIndexes.length != 0) {
+            var i = 0;
+            while (i < selection.length) {
+                var index = v_currentIndexes.indexOf(selection[i]);
+                if (index != -1) {
+                    selection[i] = index;
+                    ++i;
+                } else {
+                    selection.splice(i, 1);
+                }
+            }
+        }
+        return selection;
+    }
+}
+
+CViewModel_FilterAndSort.getHelp = function() {
+    return "This viewmodel can be used with a table to filter and sort its data. It will only work correctly if the request is not already filtered.";
+}
+
+CViewModel_FilterAndSort.providesInterface = function() {
+    return ["getUnalteredIndex", "getAlteredData", "getSort", "setSort", "getFilter", "setFilter"];
+};
+
+CViewModel_FilterAndSort.getCustomDataSchema = function() {
+    return {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Custom data for CViewModel_FilterAndSort",
+        "type": "object",
+        "properties": {
+            "sort": {
+                "type": "boolean",
+                "format": "checkbox",
+                "description": "Allow sorting the data (default true)",
+                "default": false
+            },
+            "filter": {
+                "type": "boolean",
+                "format": "checkbox",
+                "description": "Allow filtering the data (default true)",
+                "default": false
+            },
+            "initialSorting": {
+                "type": "object",
+                "description": "The initial sorting of the data",
+                "properties": {
+                    "sortBy": {
+                        "type": "integer",
+                        "description": "The index of the data we sort on",
+                        "default": 0
+                    },
+                    "sortDirection": {
+                        "type": "string",
+                        "enum": ["asc", "desc"],
+                        "description": "The direction of the sort",
+                        "default": "asc"
+                    }
+                },
+                "required": ["sortBy", "sortDirection"],
+                "additionalProperties": false
+            },
+            "initialFilter": {
+                "type": "string",
+                "description": "The initial filter string"
+            }
+        },
+        "additionalProperties": false
+    };
+};
+
+CViewModel_FilterAndSort.expectsConnection = function() {
+    return {
+        "dataConnections": [],
+        "selectionConnections": []
+    };
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_FilterAndSort.js
diff --git a/htdocs/WebApplications/CustomizableApp/ViewModels/Viewmodel_ScrollForRangeFilter.js b/htdocs/WebApplications/CustomizableApp/ViewModels/Viewmodel_ScrollForRangeFilter.js
new file mode 100644
index 0000000..04e9a41
--- /dev/null
+++ b/htdocs/WebApplications/CustomizableApp/ViewModels/Viewmodel_ScrollForRangeFilter.js
@@ -0,0 +1,67 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_ScrollForRangeFilter(p_viewmodel, p_options) {
+    "use strict";
+
+    /** constructor */
+    
+    var base = new CViewModel_Paging(p_viewmodel, p_options);
+    
+    var v_viewmodel = p_viewmodel;
+    var v_options = p_options;
+    
+    /** public functions - interface for parent */
+    
+    this.setSelectionToControl = base.setSelectionToControl;
+    this.setReponseDataPath = base.setReponseDataPath;
+    this.setBinder = base.setBinder;
+	
+	/** public functions - interface for views */
+    
+    this.getRange = function() {
+        var size = paging.getSize();
+        var max = size;
+        if (v_options.allowScrollBelow == false) {
+            max = max - paging.getRangeFilter().count + 1;
+        }
+        return {
+            "min": 0,
+            "max": max
+        };
+    };
+    
+    this.getPosition = function() {
+        return base.getRangeFilter().offset;
+    };
+    
+    this.setPosition = function(position) {
+        return base.changeFilter({"offset": {"to": position}});
+    };
+    
+    this.getViewportSize = function() {
+        return base.getRangeFilter().count;
+    };
+}
+
+CViewModel_ScrollForRangeFilter.getHelp = function() {
+    return "A viewmodel that can be used with a scrollbar to alter the rangeFilter of a request.";
+}
+
+CViewModel_ScrollForRangeFilter.providesInterface = function() {
+    return ["getRange", "getPosition", "setPosition", "getViewportSize"];
+};
+
+CViewModel_ScrollForRangeFilter.getCustomDataSchema = function() {
+    var schema = CViewModel_Paging.getCustomDataSchema();
+    scema.title = "Custom data for CViewModel_ScrollForRangeFilter";
+    return schema;
+};
+
+CViewModel_ScrollForRangeFilter.expectsConnection = function() {
+    return CViewModel_Paging.expectsConnection();
+};
+
+//# sourceURL=CustomizableApp\ViewModels\ViewModel_Scroll.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/Main.js b/htdocs/WebApplications/GuiEditor/Main.js
new file mode 100644
index 0000000..f7df73b
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Main.js
@@ -0,0 +1,135 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+var WebApplications = WebApplications || [];

+

+WebApplications.push({'application': new GuiEditor_Application()});

+

+function GuiEditor_Application() {

+    "use strict";

+

+    var v_appBase = new WebAppBase();

+    var v_webAppModel;

+

+    var jsfiles = [];

+

+    var v_extension;

+    var v_framework;

+    var v_model;

+    var v_viewmodel;

+    var v_view;

+    var v_binder;

+

+    this.info = function() {

+        return {

+            defaultIcon: "WebApplications/GuiEditor/Res/main_icon.png",

+            defaultName: "GuiEditor"

+        };

+    };

+

+    this.load = function(p_webAppModel, p_params, p_framework)  {

+        v_webAppModel = p_webAppModel;

+        v_framework = p_framework;

+

+        function appConfigLoaded(config) {

+            if (config.lastEditedApp != undefined) {

+                new JsImportFromConfigTask(config.lastEditedApp + '/AppConfig.json', v_webAppModel.getFileHandler()).taskOperation(function(ok, extension) {

+                    v_extension = extension;

+                    v_appBase.load(jsfiles, [], start, v_webAppModel.getFileHandler());

+                });

+            } else {

+                alert("Error, lastEditedApp missing from config, can't choose API.");

+            }

+        }

+

+        new MultipleDirectoryListTask(

+            [

+                "WebApplications/GuiEditor/Models",

+                "WebApplications/GuiEditor/Views",

+                "WebApplications/GuiEditor/ViewModels"

+            ],

+            v_webAppModel.getFileHandler()

+        ).taskOperation(function(ok, resources) {

+            jsfiles = resources.jsfiles;

+            v_webAppModel.loadAppConfig('CustomizableContent/GuiEditor/AppConfig.json', appConfigLoaded);

+        });

+    };

+

+    this.unload = function(webappUnloaded) {

+        function callback(exitApp) {

+            if (exitApp) { v_appBase.unload(destroy); }

+            webappUnloaded(exitApp);

+        }

+

+        v_view.unload(callback);

+    };

+

+    function destroy() {

+        v_view.destroy();

+        v_viewmodel.destroy();

+

+        v_model = undefined;

+        v_view = undefined;

+        v_viewmodel = undefined;

+        v_binder = undefined;

+    }

+

+    function start(p_callback) {

+        v_model = new GuiEditor_Model(v_webAppModel, v_framework, v_extension);

+        v_viewmodel = new GuiEditor_ViewModel(v_model);

+        v_view = new GuiEditor_View(v_viewmodel, "TSGuiFrameworkMain", "GuiEditor_MainView");

+        v_binder = new GuiEditor_Binder(v_viewmodel, v_view);

+        v_viewmodel.setBinder(v_binder);

+

+        function callback(ok, data) {

+            if (ok) {

+                v_view.applicationCreated();

+                v_binder.fullRefresh();

+            } else {

+                alert(data);

+            }

+            if (typeof p_callback === "function") {

+                p_callback();

+            }

+        }

+

+        function setupLoaded() {

+            v_viewmodel.setSetup(v_model.getSetup());

+            var taskList = new SyncTaskList([new GenericTask(v_viewmodel.init), new GenericTask(v_view.init)], callback);

+            taskList.taskOperation();

+        }

+

+        var config = v_webAppModel.getAppConfig();

+        v_webAppModel.getSetupModel().setSetupDirectory(config.lastEditedApp + '/Setups');

+        if (config.lastEditedSetup != undefined) {

+            v_model.switchSetup(config.lastEditedSetup, setupLoaded);

+        } else {

+            v_model.newSetup();

+            setupLoaded();

+        }

+    }

+}

+

+function GuiEditor_Binder(p_viewModel, p_view) {

+    "use strict";

+

+    var v_viewmodel = p_viewModel;

+    var v_view = p_view;

+

+    this.fullRefresh = function() {

+        v_view.getRequestEditorView().destroy();

+        v_view.getRequestEditorView().fullRefresh();

+        v_view.updateSetupName();

+    };

+

+    this.removeViewConnection = function(viewIndex, connectionIndex) {

+        v_view.getRequestEditorView().getEditorContainerView().removeViewConnection(viewIndex, connectionIndex);

+    };

+

+    this.selectionOrFilterChanged = function(p_path, p_selection, p_filter, p_rangeFilter, p_writableInfo) {

+        v_view.getRequestEditorView().selectionOrFilterChanged(p_path, p_selection, p_filter, p_rangeFilter, p_writableInfo);

+    };

+}

+//# sourceURL=GuiEditor\Main.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/Models/Model.js b/htdocs/WebApplications/GuiEditor/Models/Model.js
new file mode 100644
index 0000000..6f57a3a
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Models/Model.js
@@ -0,0 +1,625 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_Model(p_webAppModel, p_framework, p_extension) {

+    "use strict";

+

+    var v_baseModel = p_webAppModel;

+    var v_setupModel = v_baseModel.getSetupModel();

+    var v_framework = p_framework;

+    var v_dsRestAPI;

+

+    if (v_baseModel.getAppConfig().lastEditedApp != undefined && window["DsRestAPI"] != undefined) {

+        v_dsRestAPI = new DsRestAPI(p_extension);

+    } else {

+        v_dsRestAPI = {"getHelp": function(callback) {callback(true, {"sources" : []});}};

+    }

+

+    ///////////////////// SETUP HANDLING /////////////////////

+

+    this.newSetup = function() {

+        v_setupModel.newSetup();

+        changeLastEdited(undefined);

+        var setup = v_setupModel.getSetup();

+        fillDesktopSettings(setup);

+        return setup;

+    };

+

+    this.deleteSetup = function(name, callback) {

+        function setupDeleted(ok) {

+            var config = v_baseModel.getAppConfig();

+            if (ok && config.lastEditedSetup == name) {

+                changeLastEdited(undefined);

+            }

+            callback(ok)

+        }

+        v_setupModel.deleteSetup(name, setupDeleted);

+    };

+

+    this.switchSetup = function(p_setupName, p_setupLoaded) {

+        function setupLoaded(ok, setup, setupName) {

+            fillDesktopSettings(setup);

+            if (ok) {

+                changeLastEdited(setupName);

+            }

+            p_setupLoaded(ok, setup, setupName);

+        }

+        v_setupModel.loadSetup(p_setupName, setupLoaded, true);

+    };

+

+    this.saveSetup = v_setupModel.saveSetup;

+

+    this.saveSetupAs = function(setupName, callback) {

+        function setupSaved(ok) {

+            if (ok) {

+                changeLastEdited(setupName);

+            }

+            callback(ok);

+        }

+

+        v_setupModel.saveSetupAs(setupName, setupSaved);

+    };

+

+    this.listSetups = v_setupModel.listSetups;

+

+    this.setupExists = function(setupName, callback) {

+        v_setupModel.setupExists(setupName, callback);

+    };

+

+    function fillDesktopSettings(setup) {

+        var desktopData = setup.desktop.getData();

+        if (desktopData["ViewmodelEditors"] == undefined) {

+            desktopData["ViewmodelEditors"] = [];

+        }

+        if (desktopData["ViewEditors"] == undefined) {

+            desktopData["ViewEditors"] = [];

+        }

+        if (desktopData["Imports"] == undefined) {

+            desktopData["Imports"] = [];

+        }

+        if (desktopData["HtmlEditor"] == undefined) {

+            desktopData["HtmlEditor"] = {};

+        }

+        if (desktopData["RequestEditor"] == undefined) {

+            desktopData["RequestEditor"] = {};

+        }

+    }

+

+    function changeLastEdited(lastEdited) {

+        var config = v_baseModel.getAppConfig();

+        config.lastEditedSetup = lastEdited;

+        v_baseModel.saveAppConfig(config);

+

+        if (lastEdited != undefined) {

+            v_framework.setAppParam("DsRestAPI Console", "customization", config.lastEditedApp);

+            v_framework.setAppParam("DsRestAPI Console", "setup", config.lastEditedSetup);

+

+            var mainConfig = v_baseModel.getMainConfig();

+            for (var i = 0; i < mainConfig.availableApps.length; ++i) {

+                if (mainConfig.availableApps[i].directory == "WebApplications/CustomizableApp" && mainConfig.availableApps[i].params.customization == config.lastEditedApp) {

+                    v_framework.setAppParam(mainConfig.availableApps[i].name, "setup", config.lastEditedSetup);

+                }

+            }

+        }

+    }

+

+    this.globalSetupSearch = v_setupModel.globalSetupSearch;

+

+    this.exportChartRequest = function(callback) {

+        var exporter = new ChartRequestCreator(v_baseModel.getFileHandler(), callback);

+        exporter.run();

+    };

+

+    this.getSetup = v_setupModel.getSetup;

+

+    ///////////////////// EDITOR MODEL HANDLING /////////////////////

+

+    this.createViewModelEditor_Model = function(className, modelCreated, customData) {

+        if (customData == undefined) {

+            customData = {};

+        } else {

+            customData = mcopy(customData);

+        }

+        var data = {

+            "class": className,

+            "customData": customData,

+            "dataPathStrList": [],

+            "dataPathList": [],

+            "selectionToControlPathStrList": [],

+            "selectionToControlPathList": []

+        };

+        var setup = v_setupModel.getSetup();

+        setup.viewmodels.getData().push(data);

+        var dekstopData = {};

+        setup.desktop.getData()["ViewmodelEditors"].push(dekstopData);

+        modelCreated(new GuiEditor_ViewModelEditor_Model(data), dekstopData);

+    };

+

+    this.deleteViewModelEditor_Model = function(index) {

+        var setup = v_setupModel.getSetup();

+        setup.viewmodels.getData().splice(index, 1);

+        setup.desktop.getData()["ViewmodelEditors"].splice(index, 1);

+    };

+

+    this.createViewEditor_Model = function(className, modelCreated, customData) {

+        if (customData == undefined) {

+            customData = {};

+        } else {

+            customData = mcopy(customData);

+        }

+        var data = {

+            "class": className,

+            "customData": customData,

+            "viewModelIndexes": []

+        };

+        var setup = v_setupModel.getSetup();

+        setup.views.getData().push(data);

+        var dekstopData = {};

+        setup.desktop.getData()["ViewEditors"].push(dekstopData);

+        modelCreated(new GuiEditor_ViewEditor_Model(data), dekstopData);

+    };

+

+    this.deleteViewEditor_Model = function(index) {

+        var setup = v_setupModel.getSetup();

+        v_setupModel.getSetup().views.getData().splice(index, 1);

+        setup.desktop.getData()["ViewEditors"].splice(index, 1);

+    };

+

+    this.createImport_Model = function(setupName, modelCreated) {

+        var data = {

+            "setupName": setupName

+        };

+        var setup = v_setupModel.getSetup();

+        setup.imports.getData().push(data);

+        var dekstopData = {};

+        setup.desktop.getData()["Imports"].push(dekstopData);

+        modelCreated(new GuiEditor_Imports_Model(data), dekstopData);

+    };

+

+    this.deleteImport_Model = function(index) {

+        var setup = v_setupModel.getSetup();

+        v_setupModel.getSetup().imports.getData().splice(index, 1);

+        setup.desktop.getData()["Imports"].splice(index, 1);

+    };

+

+    this.getEditorModels = function(modelsCreated) {

+        var setup = v_setupModel.getSetup();

+        var data = {

+            "viewmodel": {

+                "models": [],

+                "desktopData": []

+            },

+            "view": {

+                "models": [],

+                "desktopData": []

+            },

+            "imports": {

+                "models": [],

+                "desktopData": []

+            }

+        }

+

+        var viewmodelInstances = setup.viewmodels.getData();

+        if (setup.desktop.getData()["ViewmodelEditors"] == undefined) {

+            setup.desktop.getData()["ViewmodelEditors"] = [];

+        }

+        data.viewmodel.desktopData = setup.desktop.getData()["ViewmodelEditors"];

+        for (var i = 0; i < viewmodelInstances.length; ++i) {

+            data.viewmodel.models.push(new GuiEditor_ViewModelEditor_Model(viewmodelInstances[i]));

+            if (data.viewmodel.desktopData[i] == undefined) {

+                data.viewmodel.desktopData[i] = {};

+            }

+        }

+

+        var viewInstances = setup.views.getData();

+        if (setup.desktop.getData()["ViewEditors"] == undefined) {

+            setup.desktop.getData()["ViewEditors"] = [];

+        }

+        data.view.desktopData = setup.desktop.getData()["ViewEditors"];

+        for (var j = 0; j < viewInstances.length; ++j) {

+            data.view.models.push(new GuiEditor_ViewEditor_Model(viewInstances[j]));

+            if (data.view.desktopData[j] == undefined) {

+                data.view.desktopData[j] = {};

+            }

+        }

+

+        var imports = setup.imports.getData();

+        if (setup.desktop.getData()["Imports"] == undefined) {

+            setup.desktop.getData()["Imports"] = [];

+        }

+        data.imports.desktopData = setup.desktop.getData()["Imports"];

+        for (var j = 0; j < imports.length; ++j) {

+            data.imports.models.push(new GuiEditor_Imports_Model(imports[j]));

+            if (data.imports.desktopData[j] == undefined) {

+                data.imports.desktopData[j] = {};

+            }

+        }

+

+        modelsCreated(data);

+    };

+

+    ///////////////////// RESOURCE HANDLING /////////////////////

+

+    this.viewExists = function(viewName, callback) {

+        function filesArrived(views) {

+            callback(views.indexOf(viewName) != -1);

+        }

+

+        this.listCustomViews(filesArrived);

+    };

+

+    this.viewmodelExists = function(viewmodelName, callback) {

+        function filesArrived(viewmodels) {

+            callback(viewmodels.indexOf(viewmodelName) != -1);

+        }

+

+        this.listCustomViewmodels(filesArrived);

+    };

+

+    function listJavascriptResources(locations, callback) {

+        new MultipleDirectoryListTask(locations, v_baseModel.getFileHandler()).taskOperation(function(ok, resources) {

+            callback(resources.jsfiles);

+        });

+    }

+

+    this.listViews = function(callback) {

+        listJavascriptResources([

+                "WebApplicationFramework/Views",

+                "WebApplications/CustomizableApp/Views",

+                v_baseModel.getAppConfig().lastEditedApp + "/Views"

+            ], callback

+        );

+    };

+

+    this.listCustomViews = function(callback) {

+        function filesArrived(views) {

+            var result = [];

+            for (var i = 0; i < views.length; ++i) {

+                var fileName = views[i].fileName;

+                if (fileName.endsWith(".js") || fileName.endsWith(".css") || fileName.endsWith(".html")) {

+                    result.push(fileName.substring(fileName.lastIndexOf("/") + 1, fileName.lastIndexOf(".")));

+                }

+            }

+            result = uniq(result);

+            result.sort();

+            callback(result);

+        }

+        v_baseModel.getFileHandler().getDirectory(v_baseModel.getAppConfig().lastEditedApp + "/Views", filesArrived);

+    };

+

+    this.listViewmodels = function(callback) {

+        listJavascriptResources([

+                "WebApplicationFramework/ViewModels",

+                "WebApplications/CustomizableApp/ViewModels",

+                v_baseModel.getAppConfig().lastEditedApp + "/ViewModels"

+            ], callback

+        );

+    };

+

+    this.listCustomViewmodels = function(callback) {

+        function filesArrived(viewmodels) {

+            var result = [];

+            for (var i = 0; i < viewmodels.length; ++i) {

+                var fileName = viewmodels[i].fileName;

+                if (fileName.endsWith(".js")) {

+                    result.push(fileName.substring(fileName.lastIndexOf("/") + 1));

+                }

+            }

+            result.sort();

+            callback(result);

+        }

+        v_baseModel.getFileHandler().getDirectory(v_baseModel.getAppConfig().lastEditedApp + "/ViewModels", filesArrived);

+    };

+

+    this.getViewUrl = function(name) {

+        return v_baseModel.getAppConfig().lastEditedApp + "/Views/" + name;

+    };

+

+    this.getViewmodelUrl = function(name) {

+        return v_baseModel.getAppConfig().lastEditedApp + "/ViewModels/" + name;

+    };

+

+    this.deleteFile = function(file, callback) {

+        v_baseModel.getFileHandler().delDirectory(file, callback);

+    };

+

+    ///////////////////// CONFIG HANDLING /////////////////////

+

+    this.getAppConfig = v_baseModel.getAppConfig;

+

+    this.setEditedApp = function(app, callback) {

+        var config = v_baseModel.getAppConfig();

+        config.lastEditedApp = app;

+        v_setupModel.setSetupDirectory(app + "/Setups");

+        v_baseModel.saveAppConfig();

+        new JsImportFromConfigTask(app + '/AppConfig.json', v_baseModel.getFileHandler()).taskOperation(function(ok, extension) {

+            if (window["DsRestAPI"] != undefined) {

+                v_dsRestAPI = new DsRestAPI(extension);

+            }

+            callback(true);

+        });

+    };

+

+    this.listEditableApps = function(callback) {

+        var result = [];

+        var mainConfig = v_baseModel.getMainConfig();

+        for (var i = 0; i < mainConfig.availableApps.length; ++i) {

+            if (mainConfig.availableApps[i].directory == "WebApplications/CustomizableApp" && mainConfig.availableApps[i].params.customization != undefined) {

+                result.push(mainConfig.availableApps[i].params.customization);

+            }

+        }

+        callback(result);

+    };

+

+    this.listEditableConfigs = function(callback) {

+        var result = [{

+            "config": "CustomizableContent/MainConfig.json",

+            "schema": "CustomizableContent/MainConfigSchema.json"

+        }];

+        function filesArrived(data) {

+            for (var i = 0; i < data.length; ++i) {

+                if (data[i].contentType.endsWith("d")) {

+                    result.push({

+                        "config": data[i].fileName + "/AppConfig.json",

+                        "schema": data[i].fileName + "/AppConfigSchema.json"

+                    });

+                }

+            }

+            callback(result);

+        }

+        v_baseModel.getFileHandler().getDirectory("CustomizableContent", filesArrived);

+    };

+

+    ///////////////////// USEFUL FUNCTIONS FOR VIEWMODELS /////////////////////

+

+    this.getDesktopDataForRequestEditor = function() {

+        return v_setupModel.getSetup().desktop.getData()["RequestEditor"];

+    };

+

+    function compareOptions(option1, option2) {

+        if (option1.text < option2.text) {

+            return -1;

+        } else if (option1.text > option2.text) {

+            return 1;

+        } else {

+            return 0;

+        }

+    }

+

+    this.sortOptions = function(options) {

+        options.sort(compareOptions);

+    };

+

+    this.getDsRestAPI = function() {

+        return v_dsRestAPI;

+    };

+

+    this.getFileHandler = v_baseModel.getFileHandler;

+}

+

+function ChartRequestCreator(p_fileHandler, p_callback) {

+    var v_fileHandler = p_fileHandler;

+    var v_callback = p_callback;

+

+    // setup name -> setup params or null

+    var v_setupsToCheckForCharts = {};

+    var v_setupsImported = {};

+    var v_showOtherSetups = false;

+    var v_setupList;

+

+    var v_chartRequest = [];

+

+    var v_setupLoader = new CSetup_Model(v_fileHandler);

+    var v_chartSaver = new JsonLoader("CustomizableContent/CustomizableApp/TimelineRequest.json", v_fileHandler, v_chartRequest);

+

+    this.run = function() {

+        function setupsListed(setups) {

+            v_setupList = setups;

+            var tasks = [];

+            for (var i = 0; i < setups.length; ++i) {

+                tasks.push(new CheckSetupForSetupTabsTask(setups[i]));

+            }

+            var taskList = new SyncTaskList(tasks, setupsCollected);

+            taskList.taskOperation();

+        }

+

+        v_setupLoader.listSetups(setupsListed);

+    };

+

+    function CheckSetupForSetupTabsTask(p_setupName) {

+        var v_setupName = p_setupName;

+        this.taskOperation = function(callback) {

+            function setupLoaded(ok, setup, setupName) {

+                if (ok) {

+                    checkSetupForSetupTabs(setup.viewmodels.getData(), setup.imports.getData());

+                    callback(true);

+                } else {

+                    callback(false, "Could not load setup: " + setupName);

+                }

+            }

+

+            v_setupLoader.loadSetup(v_setupName, setupLoaded, true);

+        }

+    }

+

+    function checkSetupForSetupTabs(viewmodels, imports) {

+        for (var i = 0; i < viewmodels.length; ++i) {

+            if (viewmodels[i].class == "CViewModel_SetupTabs" && viewmodels[i].customData.hierarchy != undefined) {

+                collectSetups(viewmodels[i].customData.hierarchy.menuElements);

+            }

+            if (viewmodels[i].class == "CViewModel_SetupTabs" && viewmodels[i].customData.displayOtherSetups == true) {

+                v_showOtherSetups = true;

+            }

+        }

+

+        for (var i = 0; i < imports.length; ++i) {

+            v_setupsImported[imports[i].setupName] = true;

+        }

+    }

+

+    function collectSetups(menuElements) {

+        if (menuElements != undefined) {

+            for (var i = 0; i < menuElements.length; ++i) {

+                if (menuElements[i].setupName != undefined) {

+                    if (menuElements[i].setupParams != undefined) {

+                        v_setupsToCheckForCharts[menuElements[i].setupName] = menuElements[i].setupParams;

+                    } else {

+                        v_setupsToCheckForCharts[menuElements[i].setupName] = null;

+                    }

+                }

+                collectSetups(menuElements[i].menuElements);

+            }

+        }

+    }

+

+    function setupsCollected() {

+        if (v_showOtherSetups) {

+            for (var i = 0; i < v_setupList.length; ++i) {

+                if (!v_setupsImported.hasOwnProperty(v_setupList[i]) && !v_setupsToCheckForCharts.hasOwnProperty(v_setupList[i])) {

+                    v_setupsToCheckForCharts[v_setupList[i]] = null;

+                }

+            }

+        }

+

+        var tasks = [];

+        for (var setup in v_setupsToCheckForCharts) {

+            tasks.push(new FindChartsTask(setup, v_setupsToCheckForCharts[setup]));

+        }

+        var taskList = new SyncTaskList(tasks, chartsFound);

+        taskList.taskOperation();

+    }

+

+    function FindChartsTask(p_setupName, p_setupParams) {

+        var v_setupName = p_setupName;

+        var v_setupParams = p_setupParams;

+        this.taskOperation = function(callback) {

+            function setupLoaded(ok, setup, setupName) {

+                if (ok) {

+                    findCharts(setup.viewmodels.getData(), setup.request.getData(), setup.request.getData(), []);

+                    callback(true);

+                } else {

+                    callback(false, "Could not load setup: " + setupName);

+                }

+            }

+

+            v_setupLoader.loadSetup(v_setupName, setupLoaded, false, true);

+        }

+    }

+

+    function findCharts(viewmodels, request, requests, path) {

+        if (requests != undefined) {

+            for (var i = 0; i < requests.length; ++i) {

+                path.push(i);

+                cleanRequestUp(requests[i], viewmodels, path);

+                if (requests[i].getData.timeline != undefined) {

+                    addChartRequest(mcopy(request), path);

+                }

+

+                findCharts(viewmodels, request, requests[i].getData.children, path);

+                path.pop();

+            }

+        }

+    }

+

+    function cleanRequestUp(request, viewmodels, path) {

+        request.getData.filter = undefined;

+        request.getData.rangeFilter = undefined;

+

+        var selectionIsChanged = false;

+        for (var i = 0; i < viewmodels.length; ++i) {

+            for (var j = 0; j < viewmodels[i].selectionToControlPathList.length; ++j) {

+                if (pathEquals(path, viewmodels[i].selectionToControlPathList[j])) {

+                    selectionIsChanged = true;

+                }

+            }

+        }

+

+        if (selectionIsChanged) {

+            request.getData.selection = undefined;

+        }

+    }

+

+    function pathEquals(path1, path2) {

+        if (path1.length == path2.length) {

+            for (var i = 0; i < path1.length; ++i) {

+                if (path1[i] != path2[i]) {

+                    return false;

+                }

+            }

+            return true;

+        } else {

+            return false;

+        }

+    }

+

+    function addChartRequest(request, path) {

+        var requestList = [request.splice(path[0], 1)[0]];

+        var currentRequest = requestList[0];

+        for (var i = 1; i < path.length; ++i) {

+            requestList[i] = currentRequest.getData.children.splice(path[i], 1)[0];

+            currentRequest = requestList[i];

+        }

+        for (var i = 0; i < requestList.length - 1; ++i) {

+            requestList[i].getData.children = [];

+        }

+

+        v_chartRequest.push(createRequestFromList(requestList));

+    }

+

+    function createRequestFromList(requestList) {

+        var PATTERN = /%Parent(\d+)%/g;

+

+        var used = [];

+        var toCheck = [requestList.length - 1];

+

+        while (toCheck.length > 0) {

+            var index = toCheck.shift();

+            used[index] = true;

+

+            var pattern = new RegExp(PATTERN);

+            var str = JSON.stringify(requestList[index]);

+            var match = pattern.exec(str);

+            while (match != undefined) {

+                var parentid = parseInt(match[1], 10);

+                if (parentid < index) {

+                    toCheck.push(parentid);

+                }

+                match = pattern.exec(str);

+            }

+        }

+

+        var newRequest;

+        var prev;

+        var k = 0;

+        for (var i = 0; i < used.length; ++i) {

+            if (used[i] != undefined) {

+                for (var j = i + 1; j < requestList.length; ++j) {

+                    var string = JSON.stringify(requestList[j]);

+                    string = string.replace("%Parent" + i + "::idx%", "%Parent" + k + "::idx%");

+                    string = string.replace("%Parent" + i + "%", "%Parent" + k + "%");

+                    requestList[j] = JSON.parse(string);

+                }

+

+                if (prev == undefined) {

+                    newRequest = requestList[i];

+                    prev = newRequest;

+                } else {

+                    prev.getData.children = [requestList[i]];

+                }

+                prev = requestList[i];

+                ++k;

+            }

+        }

+

+        return newRequest;

+    }

+

+    function chartsFound() {

+        v_chartSaver.save();

+        v_callback();

+    }

+}

+

+//# sourceURL=GuiEditor\Models\Model.js

diff --git a/htdocs/WebApplications/GuiEditor/Models/Model_Imports.js b/htdocs/WebApplications/GuiEditor/Models/Model_Imports.js
new file mode 100644
index 0000000..8660388
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Models/Model_Imports.js
@@ -0,0 +1,109 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_Imports_Model(parsedData) {
+    "use strict";
+
+    var v_imports = parsedData;
+
+    this.getSetupName = function() {
+        return v_imports["setupName"];
+    };
+
+    this.setSetup = function(p_setup) {
+        v_imports["setupName"] = p_setup;
+    };
+
+    this.setRequestPath = function(p_path) {
+        v_imports["requetsPath"] = p_path;
+    };
+
+    this.getRequestPath = function() {
+        return v_imports["requetsPath"];
+    };
+
+    this.getParentId = function() {
+        return v_imports.parentID;
+    };
+
+    this.setParentId = function(p_id) {
+        v_imports.parentID = p_id;
+    };
+
+    this.getSetupParams = function() {
+        if (v_imports.setupParams == undefined) {
+            return {};
+        } else {
+            return v_imports.setupParams;
+        }
+    };
+
+    this.addSetupParam = function(name, value) {
+        if (v_imports.setupParams == undefined) {
+            v_imports.setupParams = {};
+        }
+        v_imports.setupParams[name] = value;
+    };
+
+    this.removeSetupParam = function(name) {
+        if (v_imports.setupParams != undefined) {
+            v_imports.setupParams[name] = undefined;
+        }
+
+        if (Object.keys(v_imports.setupParams).length == 0) {
+            v_imports.setupParams = undefined;
+        }
+    };
+
+    this.getDescriptorCopy = function() {
+        return mcopy(v_imports);
+    };
+
+    this.updatePaths = function(prefix, amount) {
+        var connection = v_imports["requetsPath"];
+        if (connection != undefined) {
+            if (amount == -1 && hasPrefix(connection, prefix)) {
+                v_imports["requetsPath"] = undefined;
+                return true;
+            }
+            var pos = prefix.pop();
+            updateConnection(connection, prefix, pos, amount);
+            return false;
+        } else {
+            return false;
+        }
+    };
+
+    function updateConnection(connection, prefix, pos, amount) {
+        if (hasPrefix(connection, prefix) && connection[prefix.length] != undefined && connection[prefix.length] >= pos) {
+            connection[prefix.length] += amount;
+        }
+    }
+
+    this.pathsMoved = function(fromPrefix, fromPrefixStr, toPrefix, toPrefixStr) {
+        var connection = v_imports["requetsPath"];
+        if (connection != undefined) {
+            var origSiblingPrefix = mcopy(fromPrefix);
+            var origPosition = origSiblingPrefix.pop();
+
+            // This is the trick... we have to update the toPrefix, since we removed the node in fromPrefix
+            updateConnection(toPrefix, origSiblingPrefix, origPosition, -1);
+
+            var newSiblingPrefix = mcopy(toPrefix);
+            var newPosition = newSiblingPrefix.pop();
+            
+            if (hasPrefix(connection, fromPrefix)) {
+                connection.splice(0, fromPrefix.length);
+                for (var i = toPrefix.length - 1; i >= 0; --i) {
+                    connection.unshift(toPrefix[i]);
+                }
+            } else {
+                updateConnection(connection, origSiblingPrefix, origPosition, -1);
+                updateConnection(connection, newSiblingPrefix, newPosition, 1);
+            }
+        }
+    };
+}
+//# sourceURL=GuiEditor\Models\Model_Imports.js
diff --git a/htdocs/WebApplications/GuiEditor/Models/Model_ViewEditor.js b/htdocs/WebApplications/GuiEditor/Models/Model_ViewEditor.js
new file mode 100644
index 0000000..9220d18
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Models/Model_ViewEditor.js
@@ -0,0 +1,94 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_ViewEditor_Model(parsedData) {

+    "use strict";

+

+    var v_viewInstance = parsedData;

+

+    if (v_viewInstance.viewModelIndexes == undefined) {

+        v_viewInstance.viewModelIndexes = [];

+    }

+

+    if (v_viewInstance.idsCreating == undefined) {

+        v_viewInstance.idsCreating = [];

+    }

+

+    this.addViewModelIndex = function(p_viewModelIndex, p_index) {

+        v_viewInstance.viewModelIndexes.splice(p_index, 0, p_viewModelIndex);

+    };

+

+    this.deleteViewModelIndexFromPosition = function(p_index) {

+        v_viewInstance.viewModelIndexes.splice(p_index, 1);

+    };

+

+    this.viewModelDeleted = function(p_viewModelIndex) {

+        var i = 0;

+        while (i < v_viewInstance.viewModelIndexes.length) {

+            if (v_viewInstance.viewModelIndexes[i] === p_viewModelIndex) {

+                this.deleteViewModelIndexFromPosition(i);

+            } else if (v_viewInstance.viewModelIndexes[i] > p_viewModelIndex) {

+                --v_viewInstance.viewModelIndexes[i];

+                ++i;

+            } else {

+                ++i;

+            }

+        }

+    };

+

+    this.connectionOrderChanged = function(fromIndex, toIndex) {

+        var index = v_viewInstance.viewModelIndexes.splice(fromIndex, 1)[0];

+        v_viewInstance.viewModelIndexes.splice(toIndex, 0, index);

+    };

+

+    this.getViewModelIndexes = function() {

+        return v_viewInstance.viewModelIndexes;

+    };

+

+    this.getCustomData = function() {

+        return v_viewInstance.customData;

+    };

+

+    this.setCustomData = function(data) {

+        v_viewInstance.customData = data;

+    };

+

+    this.getClassName = function() {

+        return v_viewInstance["class"];

+    };

+

+    this.setClass = function(p_class) {

+        v_viewInstance["class"] = p_class;

+    };

+

+    this.getParentId = function() {

+        return v_viewInstance.parentID;

+    }

+

+    this.setParentId = function(p_id) {

+        v_viewInstance.parentID = p_id;

+    };

+

+    this.addChildView = function(p_id) {

+        v_viewInstance.idsCreating.push(p_id);

+    };

+

+    this.removeChildView = function() {

+        v_viewInstance.idsCreating.pop();

+    };

+

+    this.renameChildId = function(p_index, p_to) {

+        v_viewInstance.idsCreating[p_index] = p_to;

+    };

+

+    this.getChildIds = function() {

+        return v_viewInstance.idsCreating;

+    };

+

+    this.getDescriptorCopy = function() {

+        return mcopy(v_viewInstance);

+    };

+}

+//# sourceURL=GuiEditor\Models\Model_ViewEditor.js

diff --git a/htdocs/WebApplications/GuiEditor/Models/Model_ViewModelEditor.js b/htdocs/WebApplications/GuiEditor/Models/Model_ViewModelEditor.js
new file mode 100644
index 0000000..80e204b
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Models/Model_ViewModelEditor.js
@@ -0,0 +1,212 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_ViewModelEditor_Model(parsedData) {

+    "use strict";

+

+    var v_viewModelInstance = parsedData;

+    var v_this = this;

+

+    this.addDataPath = function(strpath, path, index) {

+        v_viewModelInstance.dataPathStrList.splice(index, 0, strpath);

+        v_viewModelInstance.dataPathList.splice(index, 0, path);

+    };

+

+    this.deleteDataPath = function(index) {

+        v_viewModelInstance.dataPathStrList.splice(index, 1);

+        v_viewModelInstance.dataPathList.splice(index, 1);

+    };

+

+    this.moveDataPath = function(fromIndex, toIndex) {

+        var path = v_viewModelInstance.dataPathList.splice(fromIndex, 1)[0];

+        v_viewModelInstance.dataPathList.splice(toIndex, 0, path);

+        var strpath = v_viewModelInstance.dataPathStrList.splice(fromIndex, 1)[0];

+        v_viewModelInstance.dataPathStrList.splice(toIndex, 0, strpath);

+    };

+

+    this.addSelectionPath = function(strpath, path, index) {

+        v_viewModelInstance.selectionToControlPathStrList.splice(index, 0, strpath);

+        v_viewModelInstance.selectionToControlPathList.splice(index, 0, path);

+    };

+

+    this.deleteSelectionPath = function(index) {

+        v_viewModelInstance.selectionToControlPathStrList.splice(index, 1);

+        v_viewModelInstance.selectionToControlPathList.splice(index, 1);

+    };

+

+    this.moveSelectionPath = function(fromIndex, toIndex) {

+        var path = v_viewModelInstance.selectionToControlPathList.splice(fromIndex, 1)[0];

+        v_viewModelInstance.selectionToControlPathList.splice(toIndex, 0, path);

+        var strpath = v_viewModelInstance.selectionToControlPathStrList.splice(fromIndex, 1)[0];

+        v_viewModelInstance.selectionToControlPathStrList.splice(toIndex, 0, strpath);

+    };

+

+    this.deleteConnectionsWithPrefix = function(prefix) {

+        var deleted = [];

+        deleteConnectionsWithPrefixFromList(v_viewModelInstance.dataPathList, prefix, this.deleteDataPath, deleted, "data");

+        deleteConnectionsWithPrefixFromList(v_viewModelInstance.selectionToControlPathList, prefix, this.deleteSelectionPath, deleted, "selection");

+        return deleted;

+    };

+

+    function deleteConnectionsWithPrefixFromList(list, prefix, deleteFunction, listOfDeleted, type) {

+        var i = 0;

+        while (i < list.length) {

+            if (hasPrefix(list[i], prefix)) {

+                deleteFunction(i);

+                listOfDeleted.unshift({

+                    "type": type,

+                    "index": i

+                });

+            } else {

+                ++i;

+            }

+        }

+    }

+

+    this.updateConnections = function(prefix, amount) {

+        var pos = prefix.pop();

+        updateConnectionsInList(v_viewModelInstance.dataPathList, prefix, pos, amount);

+        updateConnectionsInList(v_viewModelInstance.selectionToControlPathList, prefix, pos, amount);

+    };

+

+    function updateConnectionsInList(list, prefix, pos, amount) {

+        for (var i = 0; i < list.length; ++i) {

+            updateConnection(list[i], prefix, pos, amount);

+        }

+    }

+

+    function updateConnection(connection, prefix, pos, amount) {

+        if (hasPrefix(connection, prefix) && connection[prefix.length] != undefined && connection[prefix.length] >= pos) {

+            connection[prefix.length] += amount;

+        }

+    }

+

+    this.prefixChanged = function(fromPrefix, fromPrefixStr, toPrefix, toPrefixStr) {

+        var origSiblingPrefix = mcopy(fromPrefix);

+        var origPosition = origSiblingPrefix.pop();

+

+        // This is the trick... we have to update the toPrefix, since we removed the node in fromPrefix

+        updateConnection(toPrefix, origSiblingPrefix, origPosition, -1);

+

+        var newSiblingPrefix = mcopy(toPrefix);

+        var newPosition = newSiblingPrefix.pop();

+

+        prefixChangedInList(v_viewModelInstance.dataPathList, v_viewModelInstance.dataPathStrList, fromPrefix, fromPrefixStr, toPrefix, toPrefixStr, origSiblingPrefix, origPosition, newSiblingPrefix, newPosition);

+        prefixChangedInList(v_viewModelInstance.selectionToControlPathList, v_viewModelInstance.selectionToControlPathStrList, fromPrefix, fromPrefixStr, toPrefix, toPrefixStr, origSiblingPrefix, origPosition, newSiblingPrefix, newPosition);

+    };

+

+    function prefixChangedInList(list, strlist, fromPrefix, fromPrefixStr, toPrefix, toPrefixStr, origSiblingPrefix, origPosition, newSiblingPrefix, newPosition) {

+        for (var i = 0; i < list.length; ++i) {

+            var connection = list[i];

+            // This is simple: we change the fromPrefix to toPrefix

+            // or update the prefix: a node was deleted and a new node was added, we already know how to update it...

+            if (hasPrefix(connection, fromPrefix)) {

+                replacePrefix(list, strlist, i, fromPrefix, fromPrefixStr, toPrefix, toPrefixStr);

+            } else {

+                updateConnection(connection, origSiblingPrefix, origPosition, -1);

+                updateConnection(connection, newSiblingPrefix, newPosition, 1);

+            }

+        }

+    }

+

+    function replacePrefix(list, strlist, index, fromPrefix, fromPrefixStr, toPrefix, toPrefixStr) {

+        var connection = list[index];

+        connection.splice(0, fromPrefix.length);

+        for (var i = toPrefix.length - 1; i >= 0; --i) {

+            connection.unshift(toPrefix[i]);

+        }

+

+        var connectionStrSplit = strlist[index].split(".");

+        var fromPrefixStrSplit = fromPrefixStr.split(".");

+        fromPrefixStrSplit.pop();

+        var toPrefixStrSplit = toPrefixStr.split(".");

+        connectionStrSplit.splice(0, fromPrefixStrSplit.length);

+        for (var i = toPrefixStrSplit.length - 1; i >= 0; --i) {

+            connectionStrSplit.unshift(toPrefixStrSplit[i]);

+        }

+        var newRepresentation = joinStringAtDot(connectionStrSplit);

+        if (newRepresentation[0] === ".") {

+            newRepresentation = newRepresentation.substring(1);

+        }

+        strlist[index] = newRepresentation;

+    }

+

+    function joinStringAtDot(splitString) {

+        if (splitString.length === 0) return "";

+        var joined = splitString[0];

+        for (var i = 1; i < splitString.length; ++i) {

+            joined += "." + splitString[i];

+        }

+        return joined;

+    }

+

+    this.getDataConnections = function() {

+        return v_viewModelInstance.dataPathList;

+    };

+

+    this.getDataConnectionsStr = function() {

+        return v_viewModelInstance.dataPathStrList;

+    };

+

+    this.getSelectionConnections = function() {

+        return v_viewModelInstance.selectionToControlPathList;

+    };

+

+    this.getSelectionConnectionsStr = function() {

+        return v_viewModelInstance.selectionToControlPathStrList;

+    };

+

+    this.getCustomData = function() {

+        return v_viewModelInstance.customData;

+    };

+

+    this.setCustomData = function(data) {

+        v_viewModelInstance.customData = data;

+    };

+

+    this.getClassName = function() {

+        return v_viewModelInstance["class"];

+    };

+

+    this.setClass = function(p_class, p_callback) {

+        v_viewModelInstance["class"] = p_class;

+    };

+

+    this.requestRenamed = function(p_path, name) {

+        var changedData = [];

+        for (var i = 0; i < v_viewModelInstance.dataPathList.length; ++i) {

+            if (hasPrefix(v_viewModelInstance.dataPathList[i], p_path)) {

+                renameStringRepresentation(v_viewModelInstance.dataPathStrList, i, p_path.length - 1, name);

+                if (v_viewModelInstance.dataPathList[i].length === p_path.length) {

+                    changedData.push(i);

+                }

+            }

+        }

+

+        var changedSelection = [];

+        for (var i = 0; i < v_viewModelInstance.selectionToControlPathList.length; ++i) {

+            if (hasPrefix(v_viewModelInstance.selectionToControlPathList[i], p_path)) {

+                renameStringRepresentation(v_viewModelInstance.selectionToControlPathStrList, i, p_path.length - 1, name);

+                if (v_viewModelInstance.selectionToControlPathList[i].length === p_path.length) {

+                    changedSelection.push(i);

+                }

+            }

+        }

+

+        return {"data": changedData, "selection": changedSelection};

+    };

+

+    this.getDescriptorCopy = function() {

+        return mcopy(v_viewModelInstance);

+    };

+

+    function renameStringRepresentation(list, index, toChangeIndex, name) {

+        var splitString = list[index].split(".");

+        splitString[toChangeIndex] = name;

+        var newRepresentation = joinStringAtDot(splitString);

+        list[index] = newRepresentation;

+    }

+}

+//# sourceURL=GuiEditor\Models\Model_ViewModelEditor.js

diff --git a/htdocs/WebApplications/GuiEditor/Res/configure.png b/htdocs/WebApplications/GuiEditor/Res/configure.png
new file mode 100644
index 0000000..c2fbc63
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Res/configure.png
Binary files differ
diff --git a/htdocs/WebApplications/GuiEditor/Res/legend_connection_VM_V.png b/htdocs/WebApplications/GuiEditor/Res/legend_connection_VM_V.png
new file mode 100644
index 0000000..c2815bb
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Res/legend_connection_VM_V.png
Binary files differ
diff --git a/htdocs/WebApplications/GuiEditor/Res/legend_connection_V_V.png b/htdocs/WebApplications/GuiEditor/Res/legend_connection_V_V.png
new file mode 100644
index 0000000..b659642
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Res/legend_connection_V_V.png
Binary files differ
diff --git a/htdocs/WebApplications/GuiEditor/Res/legend_connection_V_html.png b/htdocs/WebApplications/GuiEditor/Res/legend_connection_V_html.png
new file mode 100644
index 0000000..40dcd2f
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Res/legend_connection_V_html.png
Binary files differ
diff --git a/htdocs/WebApplications/GuiEditor/Res/legend_connection_import_request.png b/htdocs/WebApplications/GuiEditor/Res/legend_connection_import_request.png
new file mode 100644
index 0000000..3810b27
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Res/legend_connection_import_request.png
Binary files differ
diff --git a/htdocs/WebApplications/GuiEditor/Res/legend_connection_request.png b/htdocs/WebApplications/GuiEditor/Res/legend_connection_request.png
new file mode 100644
index 0000000..c995d41
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Res/legend_connection_request.png
Binary files differ
diff --git a/htdocs/WebApplications/GuiEditor/Res/legend_connection_selection.png b/htdocs/WebApplications/GuiEditor/Res/legend_connection_selection.png
new file mode 100644
index 0000000..938684c
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Res/legend_connection_selection.png
Binary files differ
diff --git a/htdocs/WebApplications/GuiEditor/Res/main_icon.png b/htdocs/WebApplications/GuiEditor/Res/main_icon.png
new file mode 100644
index 0000000..04acb02
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Res/main_icon.png
Binary files differ
diff --git a/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel.js b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel.js
new file mode 100644
index 0000000..a8f74a3
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel.js
@@ -0,0 +1,306 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_ViewModel(p_model) {

+    "use strict";

+

+    var v_binder;

+    var v_setup;

+    var v_model = p_model;

+    var v_setupName;

+    var v_setupChanged = false;

+

+    var v_requestEditorViewModel = new GuiEditor_RequestEditor_ViewModel(v_model, this);

+    var v_editorContainer = new GuiEditor_EditorContainer_ViewModel(v_model, this);

+    var v_contentEditorViewmodel = new GuiEditor_ContentEditor_ViewModel(v_model, v_editorContainer.getSanityCheckerViewmodel());

+    var v_uiConfigEditorViewmodel = new GuiEditor_UIConfigEditor_ViewModel(v_model);

+

+    var v_history = [];

+    var v_nextHistoryEntry = 0;

+    var v_currentState;

+    var v_historyChecker;

+    var v_changes = {};

+    var v_historyEnabled = true;

+

+    var v_this = this;

+

+    ///////////////////// GETTER FOR SUBVIEWMODELS /////////////////////

+

+    this.getRequestEditorViewModel = function() {

+        return v_requestEditorViewModel;

+    };

+

+    this.getEditorContainerViewmodel = function() {

+        return v_editorContainer;

+    };

+

+    this.getContentEditorViewModel = function() {

+        return v_contentEditorViewmodel;

+    };

+

+    this.getUIConfigEditorViewmodel = function() {

+        return v_uiConfigEditorViewmodel;

+    };

+

+    ///////////////////// GENERAL VIEWMODEL FUNCTIONS /////////////////////

+

+    this.init = function(p_callback) {

+

+        function viewmodelsInitilaized() {

+            // we need to load the setup as the config loads with it, and we need that to know the locations of views and viewmodels for customizable app

+            var sanityChecker = v_editorContainer.getSanityCheckerViewmodel();

+            sanityChecker.setHelp(v_requestEditorViewModel.getRawHelp());

+            sanityChecker.init(p_callback);

+

+            resetHistory();

+            v_historyChecker = setInterval(saveState, 5000);

+        }

+

+        var taskList = new TaskList([new GenericTask(v_requestEditorViewModel.init), new GenericTask(v_editorContainer.init)], viewmodelsInitilaized);

+        taskList.taskOperation();

+    };

+

+    this.destroy = function() {

+        clearInterval(v_historyChecker);

+    }

+

+    this.setBinder = function(p_binder) {

+        v_binder = p_binder;

+        v_requestEditorViewModel.setBinder(p_binder);

+        v_editorContainer.setBinder(p_binder);

+    };

+

+    this.loadFile = v_model.getFileHandler().loadFile;

+    this.loadCss = v_model.getFileHandler().loadCss;

+    this.getAppConfig = v_model.getAppConfig;

+

+    ///////////////////// HANDLING SETUP AND APPLICATION CHANGED /////////////////////

+

+    this.isSetupChanged = function() {

+        return v_setupChanged;

+    };

+

+    this.setupChanged = function(how) {

+        v_setupChanged = true;

+        if (how != undefined && v_changes[how] == undefined) {

+            v_changes[how] = true;

+        }

+    };

+

+    this.setEditedApp = v_model.setEditedApp;

+

+    this.listEditableApps = function(callback) {

+        var result = [];

+

+        function appsListed(apps) {

+            for (var i = 0; i < apps.length; ++i) {

+                result.push({

+                    "value" : apps[i],

+                    "text" : apps[i]

+                });

+            }

+            callback(result);

+        }

+

+        v_model.listEditableApps(appsListed);

+    };

+

+

+    ///////////////////// SETUP HANDLING FUNCTIONS /////////////////////

+

+    this.newSetup = function() {

+        var setup = v_model.newSetup();

+        v_this.setSetup(setup);

+        v_binder.fullRefresh();

+        v_setupChanged = false;

+        resetHistory();

+    };

+

+    this.deleteSetup = function(directory, callback) {

+        function setupDeleted(ok) {

+            if (ok && directory == v_setupName) {

+                v_setupName = undefined;

+            }

+            callback(ok);

+        }

+        v_model.deleteSetup(directory, setupDeleted);

+    };

+

+    this.switchSetup = function(selected, callback) {

+        function setupLoaded(ok, setup, setupName) {

+            v_this.setSetup(setup);

+            v_binder.fullRefresh();

+            if (ok) {

+                v_setupChanged = false;

+            }

+            resetHistory();

+            callback(ok);

+        }

+        v_model.switchSetup(selected, setupLoaded);

+    };

+

+    this.listSetups = function(p_callback) {

+        function setupsLoaded(setups) {

+            var options = [];

+            for (var i = 0; i < setups.length; ++i) {

+                options.push({

+                    "value" : setups[i],

+                    "text" : setups[i]

+                });

+            }

+            p_callback(options);

+        }

+

+        v_model.listSetups(setupsLoaded);

+    };

+

+    this.saveSetup = function(callback) {

+        v_model.saveSetup(callback);

+        v_setupChanged = false;

+    };

+

+    this.saveSetupAs = function(name, callback) {

+        function setupSaved(ok) {

+            if (ok) {

+                v_setupName = name;

+                v_setupChanged = false;

+            }

+            callback(ok);

+        }

+

+        v_model.saveSetupAs(name, setupSaved);

+    };

+

+    this.setupExists = v_model.setupExists;

+    this.globalSetupSearch = v_model.globalSetupSearch;

+

+    this.isCurrentlyEdited = function(name) {

+        return v_setupName == name;

+    };

+

+    this.isSaveable = function() {

+        return v_setupName != undefined;

+    };

+

+    this.getSetupName = function() {

+        return v_setupName;

+    };

+

+    this.getJsonRepresentation = function() {

+        return JSON.stringify({

+            "REQUEST": v_setup.request.getData(),

+            "VIEWMODELS": v_setup.viewmodels.getData(),

+            "VIEWS": v_setup.views.getData(),

+            "IMPORTS": v_setup.imports.getData()

+        }, null, 4);

+    };

+

+    this.exportChartRequest = v_model.exportChartRequest;

+

+    this.setSetup = function(setup) {

+        v_setup = setup;

+        v_setupName = setup.name;

+        v_requestEditorViewModel.setSetup(setup);

+        v_requestEditorViewModel.setDesktopData(v_model.getDesktopDataForRequestEditor());

+        v_editorContainer.setSetup(setup);

+        v_contentEditorViewmodel.setSetup(setup);

+    }

+

+    ///////////////////// HISTORY /////////////////////

+

+    function createState() {

+        var state = {};

+        state.request = mcopy(v_setup.request.getData());

+        state.viewmodels = mcopy(v_setup.viewmodels.getData());

+        state.views = mcopy(v_setup.views.getData());

+        state.imports = mcopy(v_setup.imports.getData());

+        state.desktop = mcopy(v_setup.desktop.getData());

+        state.html = v_setup.html.getData();

+        state.css = v_setup.css.getData();

+        return state;

+    }

+

+    function getStateAsString() {

+        var state = createState();

+        state.desktop = undefined;

+        return JSON.stringify(state);

+    }

+

+    function getChangeText(changes) {

+        var text = "";

+        var count = 0;

+        for (var key in changes) {

+            ++count;

+            text += key + ", "

+        }

+        text = text.slice(0, text.length - 2);

+

+        if (count == 0) {

+            text = "Minor changes";

+        }

+        return text;

+    }

+

+    function saveState() {

+        if (v_historyEnabled) {

+            var state = createState();

+            var stateString = getStateAsString();

+            if (stateString != v_currentState) {

+                if (v_history[v_nextHistoryEntry] != undefined) {

+                    v_history = v_history.slice(0, v_nextHistoryEntry);

+                }

+                state.text = getChangeText(v_changes);

+                v_history[v_nextHistoryEntry] = state;

+                ++v_nextHistoryEntry;

+                v_currentState = stateString;

+            }

+            v_changes = {};

+        }

+    }

+

+    function resetHistory() {

+        v_nextHistoryEntry = 1;

+        var state = createState();

+        state.text = "History Beginning";

+        v_history = [state];

+        v_currentState = getStateAsString();

+    }

+

+    this.getHistory = function() {

+        return v_history;

+    };

+

+    this.getCurrentPositionInHistory = function() {

+        return v_nextHistoryEntry - 1;

+    }

+

+    this.historyEnabled = function(enabled) {

+        v_historyEnabled = enabled;

+    };

+

+    this.rewind = function(to) {

+        if (to < v_history.length) {

+            var state = v_history[to];

+            v_nextHistoryEntry = to + 1;

+            changeState(state);

+        }

+    };

+

+    function changeState(state) {

+        state = mcopy(state);

+        v_setup.request.setData(state.request);

+        v_setup.viewmodels.setData(state.viewmodels);

+        v_setup.views.setData(state.views);

+        v_setup.imports.setData(state.imports);

+        v_setup.desktop.setData(state.desktop);

+        v_setup.html.setData(state.html);

+        v_setup.css.setData(state.css);

+        v_this.setSetup(v_setup);

+        v_currentState = getStateAsString();

+        v_setupChanged = true;

+        v_binder.fullRefresh();

+    }

+}

+//# sourceURL=GuiEditor\ViewModels\ViewModel.js

diff --git a/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_ContentEditor.js b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_ContentEditor.js
new file mode 100644
index 0000000..7718510
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_ContentEditor.js
@@ -0,0 +1,392 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_ContentEditor_ViewModel(p_model, p_sanityChecker) {
+
+    var v_model = p_model;
+    var v_sanityChecker = p_sanityChecker;
+    var v_setup;
+
+    // we will store the opened FileLoaders in a hashmap whose keys will be the div ids
+    var v_fileLoaders = {};
+
+    // we also store the name-id pairs of the editors, so we can easily check whether a file is already open
+    var v_nameIds = {};
+
+    var v_viewmodelCounter = -1;
+    var v_viewCounter = -1;
+
+    this.setSetup = function(setup) {
+        v_setup = setup;
+    };
+
+    this.getFileName = function(id) {
+        return v_fileLoaders[id]["name"];
+    };
+
+    this.isSaveable = function(id) {
+        return v_fileLoaders[id]["saveable"];
+    };
+
+    this.isEdited = function(id) {
+        return v_fileLoaders[id]["edited"];
+    };
+
+    this.save = function(p_id, callback) {
+        var id = p_id;
+        function saved(ok) {
+            if (ok) {
+                v_fileLoaders[id]["edited"] = false;
+                var url = v_fileLoaders[id]["loader"].getUrl();
+                if (url.endsWith(".js")) {
+                    v_sanityChecker.addFile(url);
+                }
+            }
+            callback(ok, id);
+        }
+
+        v_fileLoaders[id]["loader"].save(undefined, undefined, saved);
+    };
+
+    function saveAs(p_id, name, url, p_callback) {
+        var id = p_id;
+        function saved(ok) {
+            if (ok) {
+                v_fileLoaders[id]["saveable"] = true;
+                v_fileLoaders[id]["edited"] = false;
+                v_fileLoaders[id]["name"] = name;
+                if (url.endsWith(".js")) {
+                    v_sanityChecker.addFile(url);
+                }
+            }
+            p_callback(ok, id);
+        }
+
+        v_fileLoaders[id]["loader"].save(undefined, url, saved);
+    }
+
+    function switchId(name, id) {
+        for (var key in v_nameIds) {
+            if (v_nameIds.hasOwnProperty(key) && v_nameIds[key] == id) {
+                v_nameIds[key] = undefined;
+                v_nameIds[name] = id;
+                break;
+            }
+        }
+    }
+
+    this.saveViewAs = function(id, name, callback) {
+
+        var existingId = v_nameIds[name];
+        if (existingId == id) {
+            existingId = undefied;
+        }
+
+        function saved(ok) {
+            if (ok) {
+                switchId(name, id);
+                callback(ok, id, existingId);
+            } else {
+                callback(ok);
+            }
+        }
+
+        function SaveTask(p_id, p_url) {
+            var id = p_id;
+            var url = p_url;
+            this.taskOperation = function(p_callback) {
+                saveAs(id, name, url, p_callback);
+            }
+        }
+
+        var taskList = new TaskList([
+            new SaveTask(id + "_Html", v_model.getViewUrl(name + ".html")),
+            new SaveTask(id + "_Css", v_model.getViewUrl(name + ".css")),
+            new SaveTask(id + "_Js", v_model.getViewUrl(name + ".js"))
+        ], saved);
+        taskList.taskOperation();
+    };
+
+    this.saveViewmodelAs = function(id, name, callback) {
+
+        if (!name.endsWith(".js")) {
+            name = name + ".js";
+        }
+        var url = v_model.getViewmodelUrl(name);
+
+        var existingId = v_nameIds[name];
+        if (existingId == id) {
+            existingId = undefied;
+        }
+
+        function saved(ok) {
+            if (ok) {
+                switchId(name, id);
+                callback(ok, id, existingId);
+            } else {
+                callback(ok);
+            }
+        }
+
+        saveAs(id, name, url, saved);
+    };
+
+    this.viewExists = function(name, callback) {
+        v_model.viewExists(name, callback);
+    };
+
+    this.viewmodelExists = function(name, callback) {
+        v_model.viewmodelExists(name + ".js", callback);
+    };
+
+    this.editorClosed = function(id) {
+        for (var key in v_fileLoaders) {
+            if (v_fileLoaders.hasOwnProperty(key) && key.startsWith(id)) {
+                v_fileLoaders[key] = undefined;
+            }
+        }
+
+        for (var name in v_nameIds) {
+            if (v_nameIds.hasOwnProperty(name) && v_nameIds[name] != undefined && v_nameIds[name].startsWith(id)) {
+                v_nameIds[name] = undefined;
+            }
+        }
+    };
+
+    this.loadViewContent = function(viewName, callback) {
+        loadView(false, viewName, callback);
+    };
+
+    this.loadViewTemplate = function(viewName, callback) {
+        loadView(true, viewName, callback);
+    }
+
+    function loadView(template, viewName, callback) {
+        if (v_nameIds[viewName] != undefined) {
+            callback(v_nameIds[viewName], viewName, "exists");
+            return;
+        }
+
+        var url = viewName;
+        if (!template) {
+            url = v_model.getViewUrl(viewName);
+        }
+
+        ++v_viewCounter;
+        var id = "GuiEditor_ViewContentEditor_File_" + v_viewCounter;
+
+        var saveable = !template;
+
+        function LoadTask(id, name, url) {
+            var v_id = id;
+            var v_name = name;
+            var v_url = url;
+
+            this.taskOperation = function(callback) {
+                loadContent(v_id, v_name, saveable, v_url, callback);
+            }
+        }
+
+        function contentAdded() {
+            v_nameIds[viewName] = id;
+            callback(id, viewName, "load");
+        }
+
+        var taskList = new TaskList([
+            new LoadTask(id + "_Html", viewName + ".html", url + ".html"),
+            new LoadTask(id + "_Css", viewName + ".css", url + ".css"),
+            new LoadTask(id + "_Js", viewName + ".js", url + ".js")
+        ], contentAdded);
+        taskList.taskOperation();
+    }
+
+    this.loadViewmodelContent = function(viewmodelName, callback) {
+        loadViewmodel(false, viewmodelName, callback);
+    };
+
+    this.loadViewmodelTemplate = function(viewmodelName, callback) {
+        loadViewmodel(true, viewmodelName, callback);
+    };
+
+    function loadViewmodel(template, viewmodelName, callback) {
+        if (!viewmodelName.endsWith(".js")) {
+            viewmodelName += ".js";
+        }
+
+        if (v_nameIds[viewmodelName] != undefined) {
+            callback(v_nameIds[viewmodelName], viewmodelName, "exists");
+            return;
+        }
+
+        var url = viewmodelName;
+        if (!template) {
+            url = v_model.getViewmodelUrl(viewmodelName);
+        }
+
+        ++v_viewmodelCounter;
+        var id = "GuiEditor_ViewmodelContentEditor_File_" + v_viewmodelCounter + "_Js";
+
+        var saveable = !template;
+
+        function contentAdded() {
+            v_nameIds[viewmodelName] = id;
+            callback(id, viewmodelName, "load");
+        }
+
+        loadContent(id, name, saveable, url, contentAdded);
+    }
+
+    function createContentOptionsFromList(list) {
+        var result = [];
+        for (var i = 0; i < list.length; ++i) {
+            result.push({
+                "value": list[i],
+                "text": list[i]
+            })
+        }
+        v_model.sortOptions(result);
+        return result;
+    }
+
+    function createTemplateOptionsFromList(list) {
+        var result = [];
+        for (var i = 0; i < list.length; ++i) {
+            result.push({
+                "value": list[i].substring(0, list[i].lastIndexOf(".")),
+                "text": list[i].substring(list[i].lastIndexOf("/") + 1, list[i].lastIndexOf("."))
+            })
+        }
+        v_model.sortOptions(result);
+        return result;
+    }
+
+    this.listViewTemplates = function(callback) {
+        v_model.listViews(function(files) {
+            callback(createTemplateOptionsFromList(files));
+        })
+    };
+
+    this.listViewmodelTemplates = function(callback) {
+        v_model.listViewmodels(function(files) {
+            callback(createTemplateOptionsFromList(files));
+        })
+    };
+
+    this.listViews = function(callback) {
+        v_model.listCustomViews(function(views) {
+            callback(createContentOptionsFromList(views));
+        });
+    };
+
+    this.listViewmodels = function(callback) {
+        v_model.listCustomViewmodels(function(viewmodels) {
+            callback(createContentOptionsFromList(viewmodels));
+        });
+    };
+
+    function addNewContent(id, name) {
+        v_fileLoaders[id] = {
+            "loader": new FileLoader(undefined, v_model.getFileHandler()),
+            "saveable": false,
+            "edited": true,
+            "name": name
+        }
+    }
+
+    function loadContent(id, name, saveable, url, callback) {
+        v_fileLoaders[id] = {
+            "loader": new FileLoader(url, v_model.getFileHandler()),
+            "saveable": saveable,
+            "edited": false,
+            "name": name
+        }
+        v_fileLoaders[id]["loader"].taskOperation(callback);
+    }
+
+    this.deleteView = function(name, callback) {
+        function deleted(ok) {
+            var id = v_nameIds[name];
+            if (ok && id != undefined) {
+                v_fileLoaders[id + "_Html"]["saveable"] = false;
+                v_fileLoaders[id + "_Css"]["saveable"] = false;
+                v_fileLoaders[id + "_Js"]["saveable"] = false;
+            }
+
+            callback(ok, id);
+        }
+
+        function DeleteTask(p_name) {
+            var v_name = p_name;
+            this.taskOperation = function(p_callback) {
+                v_model.deleteFile(v_name, p_callback);
+            }
+        }
+
+        var taskList = new TaskList([
+            new DeleteTask(v_model.getViewUrl(name + ".html")),
+            new DeleteTask(v_model.getViewUrl(name + ".css")),
+            new DeleteTask(v_model.getViewUrl(name + ".js"))
+        ], deleted);
+        taskList.taskOperation();
+    };
+
+    this.deleteViewmodel = function(name, callback) {
+        function deleted(ok) {
+            var id = v_nameIds[name];
+            if (ok && id != undefined) {
+                v_fileLoaders[id]["saveable"] = false;
+            }
+            callback(ok, id);
+        }
+        v_model.deleteFile(v_model.getViewmodelUrl(name), deleted);
+    };
+
+    this.newViewContent = function(callback) {
+        ++v_viewCounter;
+
+        var id = "GuiEditor_ViewContentEditor_File_" + v_viewCounter;
+        var name = "View_" + v_viewCounter;
+
+        addNewContent(id + "_Html", name + ".html");
+        addNewContent(id + "_Css", name + ".css");
+        addNewContent(id + "_Js", name + ".js");
+
+        v_nameIds[name] = id;
+
+        callback(id, name, "new");
+    };
+
+    this.newViewmodelContent = function(callback) {
+        ++v_viewmodelCounter;
+
+        var id = "GuiEditor_ViewmodelContentEditor_File_" + v_viewmodelCounter + "_Js";
+        var name = "Viewmodel_" + v_viewmodelCounter;
+
+        addNewContent(id, name + ".js");
+
+        v_nameIds[name] = id;
+
+        callback(id, name, "new");
+    };
+
+    this.getContent = function(id) {
+        var content = {};
+        content.text = v_fileLoaders[id]["loader"].getData();
+        if (id.endsWith("Html")) {
+            content.mode = "xml";
+        } else if (id.endsWith("Css")) {
+            content.mode = "css";
+        } else if (id.endsWith("Js")) {
+            content.mode = "javascript";
+        }
+        return content;
+    };
+
+    this.setContent = function(id, content) {
+        v_fileLoaders[id]["loader"].setData(content);
+        v_fileLoaders[id]["edited"] = true;
+    };
+}
+//# sourceURL=GuiEditor\ViewModels\ViewModel_ContentEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_EditorContainer.js b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_EditorContainer.js
new file mode 100644
index 0000000..865332a
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_EditorContainer.js
@@ -0,0 +1,246 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_EditorContainer_ViewModel(p_model, p_parent) {

+    "use strict";

+

+    var v_model = p_model;

+    var v_parent = p_parent;

+    var v_binder;

+

+    var v_viewModelBoxes = [];

+    var v_viewBoxes = [];

+    var v_importBoxes = [];

+    var v_htmlBox = new GuiEditor_HtmlEditor_ViewModel(this);

+    var v_sanityChecker = new GuiEditor_SanityChecker_ViewModel(v_model, this);

+

+    var v_this = this;

+

+    ///////////////////// GENERAL FUNCTIONS /////////////////////

+

+    this.setupChanged = function(how) {

+        v_parent.setupChanged(how);

+    };

+

+    this.init = function(p_callback) {

+        p_callback(true);

+    };

+

+    this.setBinder = function(p_binder) {

+        v_binder = p_binder;

+    };

+

+    this.setSetup = function(setup) {

+        v_htmlBox.setSetup(setup);

+        v_sanityChecker.setSetup(setup);

+    };

+

+    ///////////////////// GETTER FOR SUBVIEWMODELS /////////////////////

+

+    this.getSanityCheckerViewmodel = function() {

+        return v_sanityChecker;

+    };

+

+    this.getHtmlEditorViewmodel = function() {

+        return v_htmlBox;

+    };

+

+    ///////////////////// CREATING AND DELETING EDITORS /////////////////////

+

+    this.createViewModelEditor_ViewModel = function(className, callback, customData) {

+        function editorCreated(model, desktopData) {

+            var viewmodel = new GuiEditor_ViewModelEditor_ViewModel(model, v_this);

+            v_viewModelBoxes.push(viewmodel);

+            callback(viewmodel, desktopData);

+        }

+        v_model.createViewModelEditor_Model(className, editorCreated, customData);

+        v_parent.setupChanged("Viewmodel created");

+    };

+

+    this.deleteViewModelEditor_ViewModel = function(index) {

+        v_viewModelBoxes.splice(index, 1);

+        v_model.deleteViewModelEditor_Model(index);

+        v_parent.setupChanged("Viewmodel deleted");

+    };

+

+    this.createViewEditor_ViewModel = function(className, callback, customData) {

+        function editorCreated(model, desktopData) {

+            var viewmodel = new GuiEditor_ViewEditor_ViewModel(model, v_this);

+            v_viewBoxes.push(viewmodel);

+            callback(viewmodel, desktopData);

+        }

+        v_model.createViewEditor_Model(className, editorCreated, customData);

+        v_parent.setupChanged("View created");

+    };

+

+    this.deleteViewEditor_ViewModel = function(index) {

+        var viewmodel = v_viewBoxes.splice(index, 1)[0];

+        v_model.deleteViewEditor_Model(index);

+        deleteIdConnections(viewmodel);

+        v_parent.setupChanged("View deleted");

+    };

+

+    this.createImport_ViewModel = function(setupName, callback) {

+        function editorCreated(model, desktopData) {

+            var viewmodel = new GuiEditor_Imports_ViewModel(model, v_this);

+            v_importBoxes.push(viewmodel);

+            callback(viewmodel, desktopData);

+        }

+        v_model.createImport_Model(setupName, editorCreated);

+        v_parent.setupChanged("Import created");

+    };

+

+    this.deleteImport_ViewModel = function(index) {

+        var viewmodel = v_importBoxes.splice(index, 1)[0];

+        v_model.deleteImport_Model(index);

+        deleteIdConnections(viewmodel);

+        v_parent.setupChanged("Import deleted");

+    };

+

+    this.createViewModelsFromExistingData = function(viewModelsCreated) {

+        v_viewBoxes = [];

+        v_viewModelBoxes = [];

+        v_importBoxes = [];

+

+        function modelsArrived(data) {

+            function createViewModels(models, ClassToInit, listToAppendInto) {

+                for (var i = 0; i < models.length; ++i) {

+                    var model = models[i];

+                    var viewmodel = new ClassToInit(model, v_this);

+                    listToAppendInto.push(viewmodel);

+                }

+            }

+

+            createViewModels(data.view.models, GuiEditor_ViewEditor_ViewModel, v_viewBoxes);

+            createViewModels(data.viewmodel.models, GuiEditor_ViewModelEditor_ViewModel, v_viewModelBoxes);

+            createViewModels(data.imports.models, GuiEditor_Imports_ViewModel, v_importBoxes);

+

+            data.view.viewmodels = v_viewBoxes;

+            data.viewmodel.viewmodels = v_viewModelBoxes;

+            data.imports.viewmodels = v_importBoxes;

+

+            viewModelsCreated(data);

+        }

+

+        v_model.getEditorModels(modelsArrived);

+    };

+

+    function deleteIdConnections(viewmodel) {

+        var parentId = viewmodel.getParentId();

+        v_this.removeConnectedChild(parentId);

+        viewmodel.removeAllChildren();

+    }

+

+    ///////////////////// LISTING SETUPS, CLASSES AND FILES /////////////////////

+

+    this.getViewClassNames = function(p_callback) {

+        getResources(v_model.listViews, p_callback);

+    };

+

+    this.getViewmodelClassNames = function(p_callback) {

+        getResources(v_model.listViewmodels, p_callback);

+    };

+

+    function getResources(modelFunction, callback) {

+        var options = [];

+        function resourcesListed(data) {

+            var tasks = [];

+            for (var i = 0; i < data.length; ++i) {

+                tasks.push(new GetClassTask(data[i], options, i));

+            }

+            new TaskList(tasks, function() {callback(options);}).taskOperation();

+        }

+        modelFunction(resourcesListed);

+    }

+

+    function GetClassTask(file, options, index) {

+        var v_file = file;

+        var v_options = options;

+        var v_index = index;

+        var re = /^\s*function\s+(\w+)\s*\(/mi; // Match first function not commented out. Does not check for multiline comments!

+

+        this.taskOperation = function(callback) {

+            v_model.getFileHandler().loadFile(v_file, function(ok, content) {

+                var matches = content.replace(/\/\*[^]*?\*\//g, '').match(re);

+                if (matches != undefined && matches.length > 0) {

+                    v_options[v_index] = {

+                        "value" : matches[1],

+                        "text" : matches[1],

+                        "location": v_file

+                    };

+                }

+                callback(true);

+            });

+        };

+    };

+

+    this.listSetups = function(callback) {

+        function setupsListed(setups) {

+            var options = [];

+            for (var i = 0; i < setups.length; ++i) {

+                options.push({

+                    "value": setups[i],

+                    "text": setups[i]

+                });

+            }

+            callback(options);

+        }

+

+        v_model.listSetups(setupsListed);

+    };

+

+    this.sortOptions = v_model.sortOptions;

+

+    ///////////////////// VIEW ID MAINTENANCE /////////////////////

+

+    this.getViewEditorIndex = function(editor) {

+        return v_viewBoxes.indexOf(editor);

+    };

+

+    this.removeConnectedChild = function(parentId) {

+        for (var i = 0; i < v_viewBoxes.length; ++i) {

+            var index = v_viewBoxes[i].getChildIds().indexOf(parentId);

+            if (index != -1) {

+                v_viewBoxes[i].removeChildView(index);

+                v_binder.removeViewConnection(i, index);

+                return;

+            }

+        }

+

+        var index = v_htmlBox.getChildIds().indexOf(parentId);

+        if (index != -1) {

+            v_htmlBox.removeChildView(index);

+            v_binder.removeViewConnection(-1, index);

+        }

+    };

+

+    this.childRenamed = function(p_from, p_to) {

+        var list = v_viewBoxes.concat(v_importBoxes);

+        for (var i = 0; i < list.length; ++i) {

+            if (list[i].getParentId() == p_from) {

+                list[i].setParentId(p_to);

+                break;

+            }

+        }

+    };

+

+    ///////////////////// SANITY CHECKER FUNCTIONS /////////////////////

+

+    this.getHelp = v_sanityChecker.getHelp;

+

+    this.isValidView = function(view) {

+        var connectedViewmodels = [];

+        var viewmodelIndexes = view.getViewModelIndexes();

+        for (var i = 0; i < viewmodelIndexes.length; ++i) {

+            connectedViewmodels.push(v_viewModelBoxes[viewmodelIndexes[i]]);

+        }

+

+        return v_sanityChecker.isValidView(view, connectedViewmodels);

+    };

+

+    this.isValidViewmodel = v_sanityChecker.isValidViewmodel;

+    this.getCustomDataSchema = v_sanityChecker.getCustomDataSchema;

+}

+//# sourceURL=GuiEditor\ViewModels\ViewModel_EditorContainer.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_HtmlEditor.js b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_HtmlEditor.js
new file mode 100644
index 0000000..9952786
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_HtmlEditor.js
@@ -0,0 +1,112 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_HtmlEditor_ViewModel(p_parentViewmodel) {
+    "use strict";
+
+    var v_parentViewmodel = p_parentViewmodel;
+    var v_ids = [];
+    var setup;
+    
+    ///////////////////// GENERAL FUNCTIONS /////////////////////
+    
+    this.setSetup = function(p_setup) {
+        setup = p_setup;
+        v_ids = [];
+    };
+
+    ///////////////////// GENERAL EDITOR FUNCTIONS /////////////////////
+
+    this.getTreeData = function() {
+        var data = [];
+        for (var i = 0; i < v_ids.length; ++i) {
+            data.push({"text" : v_ids[i].id});
+        }
+        return data;
+    };
+
+    this.getName = function() {
+        return "Setup html";
+    };
+
+    this.getTooltip = this.getName;
+
+    this.matches = function(string) {
+        return JSON.stringify(setup.html.getData() + setup.css.getData()).toLowerCase().indexOf(string) != -1;
+    };
+
+    ///////////////////// GENERAL VIEW EDITOR FUNCTIONS /////////////////////
+
+    this.getChildIds = function() {
+        var list = [];
+        for (var i = 0; i < v_ids.length; ++i) {
+            list.push(v_ids[i].id);
+        }
+        return list;
+    };
+
+    this.removeChildView = function(p_index) {
+        v_parentViewmodel.childRenamed(v_ids[p_index].id);
+        v_parentViewmodel.setupChanged("Delete HTML connection");
+    };
+
+    this.removeConnectedChild = function(parentId) {
+        v_parentViewmodel.removeConnectedChild(parentId);
+    };
+
+    ///////////////////// HTML EDITOR SPECIFIC FUNCTIONS /////////////////////
+
+    this.getDesktopData = function() {
+        return setup.desktop.getData()["HtmlEditor"];
+    };
+
+    this.removeChildViewById = function(p_id) {
+        v_parentViewmodel.childRenamed(p_id);
+    };
+
+    this.getCss = function(callback) {
+        callback(setup.css.getData());
+    };
+
+    this.setCss = function(text) {
+        setup.css.setData(text);
+        v_parentViewmodel.setupChanged("CSS changed");
+    };
+
+    this.getHtml = function(callback) {
+        callback(setup.html.getData());
+    };
+
+    this.setHtml = function(text) {
+        setup.html.setData(text);
+        v_parentViewmodel.setupChanged("HTML changed");
+    };
+
+    this.collectIds = function() {
+        var newIds = [];
+        var str = setup.html.getData();
+        var parser = new DOMParser();
+        var doc = parser.parseFromString('<DIV>' + str + '</DIV>', "text/xml");
+        var elements_with_id = doc.querySelectorAll("*[id]");
+        for(var i = 0; i < elements_with_id.length; i++) {
+            newIds.push({
+                "id": elements_with_id[i].getAttribute("id"),
+                "prevIndex": findIdIndex(elements_with_id[i].getAttribute("id"))
+            });
+        }
+        v_ids = newIds;
+        return v_ids;
+    };
+
+    function findIdIndex(id) {
+        for (var i = 0; i < v_ids.length; ++i) {
+            if (v_ids[i].id === id) {
+                return i;
+            }
+        }
+        return -1;
+    }
+}
+//# sourceURL=GuiEditor\ViewModels\ViewModel_HtmlEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_Imports.js b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_Imports.js
new file mode 100644
index 0000000..4723b6b
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_Imports.js
@@ -0,0 +1,77 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_Imports_ViewModel(p_model, p_parent) {
+    "use strict";
+
+    var v_model = p_model;
+    var v_parent = p_parent;
+
+    var v_this = this;
+
+    ///////////////////// GENERAL EDITOR FUNCTIONS /////////////////////
+
+    this.getTreeData = function() {
+        var data = [
+            {"text": "Import into ..."},
+            {"text": "Request connection"},
+            {"text": "Parameters", "children": []}
+        ];
+
+        var params = v_model.getSetupParams();
+        for (var name in params) {
+            data[2].children.push({"text": name + ": " + params[name]});
+        }
+
+        return data;
+    };
+
+    this.getName = v_model.getSetupName;
+    this.getTooltip = function() {
+        return JSON.stringify(v_model.getDescriptorCopy(), null, 4);
+    };
+
+    this.matches = function(string) {
+        return JSON.stringify(v_model.getDescriptorCopy()).toLowerCase().indexOf(string) != -1;
+    };
+
+    ///////////////////// GENERAL VIEW EDITOR FUNCTIONS /////////////////////
+
+    this.getParentId = v_model.getParentId;
+
+    this.setParentId = function(p_id) {
+        v_model.setParentId(p_id);
+        v_parent.setupChanged("Parent id changed");
+    };
+
+    this.removeAllChildren = function() {};
+
+    ///////////////////// IMPORT EDITOR SPECIFIC FUNCTIONS /////////////////////
+
+    this.setupNameChanged = function(setupName) {
+        v_model.setSetup(setupName);
+        v_parent.setupChanged("Setup name changed");
+    };
+
+    this.setRequestPath = function(requestPath) {
+        v_model.setRequestPath(requestPath);
+        v_parent.setupChanged("Import request path changed");
+    };
+
+    this.getRequestPath = v_model.getRequestPath;
+    this.updatePaths = v_model.updatePaths;
+    this.pathsMoved = v_model.pathsMoved;
+
+    this.addSetupParam = function(name, value) {
+        v_model.addSetupParam(name, value);
+        v_parent.setupChanged("Import param added");
+    };
+
+    this.removeSetupParam = function(name) {
+        v_model.removeSetupParam(name);
+        v_parent.setupChanged("Import param removed");
+    };
+}
+//# sourceURL=GuiEditor\ViewModels\ViewModel_Imports.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_RequestEditor.js b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_RequestEditor.js
new file mode 100644
index 0000000..5f3b06a
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_RequestEditor.js
@@ -0,0 +1,292 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_RequestEditor_ViewModel(p_model, p_parent) {

+    "use strict";

+

+    var v_model = p_model;

+    var v_parent = p_parent;

+    var dataSourceUtils = new DataSourceUtils();

+    var v_desktopData;

+    var v_binder;

+

+    var v_help;

+    var v_requests = [];

+    var v_requestBuilder = new DSHelpToRequest_manual();

+    v_requestBuilder.setRequest(v_requests);

+

+    var v_this = this;

+

+    ///////////////////// GENERAL FUNCTIONS /////////////////////

+

+    this.init = function(p_callback) {

+        function helpArrived(ok, help) {

+            if (ok) {

+                v_help = help;

+                p_callback(true);

+            } else {

+                p_callback(false, "Error getting help");

+            }

+        }

+

+        v_model.getDsRestAPI().getHelp(helpArrived);

+    };

+

+    this.setBinder = function(p_binder) {

+        v_binder = p_binder;

+    };

+

+    this.setSetup = function(setup) {

+        v_requests = setup.request.getData();

+        v_requestBuilder.setRequest(v_requests);

+    };

+

+    ///////////////////// FUNCTIONS FOR VIEW VISUALIZATION /////////////////////

+

+    this.getHelp = function(refresh, toSort) {

+        function helpArrived(ok, p_help) {

+            if (ok) {

+                v_help = p_help;

+                var help = new HelpTreeBuilder(mcopy(v_help)).getHelpTree(toSort);

+                v_requestBuilder.setHelp(help);

+                var jsTreeData = dataSourceUtils.convertHelpToTreeDataArray(help.sources);

+                refresh(jsTreeData);

+            } else {

+                alert("Failed to get help");

+                refresh([]);

+            }

+        }

+

+        v_model.getDsRestAPI().getHelp(helpArrived);

+    };

+

+    this.getRawHelp = function() {

+        return v_help;

+    };

+

+    this.getRequestTree = function(refresh) {

+        var jsTreeData = dataSourceUtils.convertRequestToTreeDataArray(v_requests);

+        refresh(jsTreeData);

+    };

+

+    this.getFilterAsTree = function(p_path) {

+        var filter = v_requestBuilder.getFilterPart(p_path, []);

+        var treeData = [];

+        if (filter != undefined) {

+            traverseFilter(filter, treeData);

+        }

+        return treeData;

+    };

+

+    function traverseFilter(filter, treeData, paramName) {

+        var treeNode;

+        var treeNodeText = "";

+        if (paramName != undefined) {

+            treeNodeText = paramName + ": ";

+        }

+        if (filter.dataValue != undefined) {

+            treeNode = {"text": treeNodeText + filter.dataValue};

+            treeData.push(treeNode);

+        } else if (filter.request != undefined) {

+            treeNode = {"text": treeNodeText + filter.request.element, "children": []};

+            treeData.push(treeNode);

+            if (filter.request.params != undefined && filter.request.params.length > 0) {

+                for (var i = 0; i < filter.request.params.length; ++i) {

+                    traverseFilter(filter.request.params[i].paramValue, treeNode.children, filter.request.params[i].paramName);

+                }

+            }

+            if (filter.request.remapTo != undefined) {

+                traverseFilter(filter.request.remapTo, treeNode.children, "remapTo");

+            }

+        }

+    }

+

+    this.findSelectionsAndFilters = function() {

+        traverseRequest(v_requests, [], selectionOrFilterChanged);

+    };

+

+    function selectionOrFilterChanged(node, path) {

+        v_binder.selectionOrFilterChanged(path, node.getData.selection != undefined, node.getData.filter != undefined, node.getData.rangeFilter != undefined, node.getData.writableInfo != undefined);

+    }

+

+    function traverseRequest(list, path, processGetData) {

+        for (var i = 0; i < list.length; ++i) {

+            path.push(i);

+            processGetData(list[i], path);

+            if (list[i].getData.children != undefined) {

+                traverseRequest(list[i].getData.children, path, processGetData);

+            }

+            path.pop();

+        }

+    }

+

+    this.selectionAdded = function(p_path) {

+        var request = v_this.getRequestFromPath(p_path);

+        if (request.getData.selection == undefined) {

+            request.getData.selection = [0];

+        }

+        selectionOrFilterChanged(request, p_path);

+        v_parent.setupChanged("Request changed");

+    };

+

+    this.setDesktopData = function(p_data) {

+        v_desktopData = p_data;

+    };

+

+    this.getDesktopData = function() {

+        return v_desktopData;

+    };

+

+    ///////////////////// FUNCTIONS FOR REQUEST EDITING /////////////////////

+

+    this.createRequest = function(p_helpPath, p_position, partialRefresh) {

+        var request = v_requestBuilder.createRequest(p_helpPath, p_position);

+        partialRefresh([p_position], dataSourceUtils.convertRequestToTreeDataArray([request])[0]);

+        v_parent.setupChanged("Request changed");

+    };

+

+    this.createEmptyRequest = function(p_position, partialRefresh) {

+        var request = v_requestBuilder.createEmptyRequest(p_position);

+        partialRefresh([p_position], dataSourceUtils.convertRequestToTreeDataArray([request])[0]);

+        v_parent.setupChanged("Request changed");

+    };

+

+    this.addChildRequest = function(p_helpPath, p_requestPath, p_position, partialRefresh) {

+        var childRequest = v_requestBuilder.addChildRequest(p_helpPath, mcopy(p_requestPath), p_position);

+        p_requestPath.push(p_position);

+        partialRefresh(p_requestPath, dataSourceUtils.convertRequestToTreeDataArray([childRequest])[0]);

+        v_parent.setupChanged("Request changed");

+    };

+

+    this.addEmptyChildRequest = function(p_requestPath, p_position, partialRefresh) {

+        var childRequest = v_requestBuilder.addEmptyChildRequest(mcopy(p_requestPath), p_position);

+        p_requestPath.push(p_position);

+        partialRefresh(p_requestPath, dataSourceUtils.convertRequestToTreeDataArray([childRequest])[0]);

+        v_parent.setupChanged("Request changed");

+    };

+

+    this.copyRequest = function(p_path, partialRefresh) {

+        var childRequest = v_requestBuilder.copyRequest(mcopy(p_path));

+        p_path[p_path.length - 1] += 1;

+        partialRefresh(p_path, dataSourceUtils.convertRequestToTreeDataArray([childRequest])[0]);

+        v_parent.setupChanged("Request changed");

+    };

+

+    this.convertToSizeOf = function(p_path, refresh) {

+        var request = v_this.getRequestFromPath(p_path);

+        convertTo(request.getData, "sizeOf");

+        refresh(p_path, "sizeOf");

+        v_parent.setupChanged("Request changed");

+    };

+

+    this.convertToDataElementPresent = function(p_path, refresh) {

+        var request = v_this.getRequestFromPath(p_path);

+        convertTo(request.getData, "dataElementPresent");

+        refresh(p_path, "dataElementPresent");

+        v_parent.setupChanged("Request changed");

+    };

+

+    this.matches = function(string, path) {

+        var request = v_requestBuilder.getRequestCopy(path);

+        return JSON.stringify(request).toLowerCase().indexOf(string) != -1;

+    };

+

+    function convertTo(request, p_element) {

+        var source = request.source;

+        var element = request.element;

+        var ptcname = request.ptcname;

+        var params = request.params;

+        if (params == undefined) {

+            params = [];

+        }

+

+        request.source = "DataSource";

+        request.element = p_element;

+        request.ptcname = undefined;

+        request.filter = undefined;

+        request.rangeFilter = undefined;

+        request.params = [{

+            "paramName": "Source",

+            "paramValue": source

+        }, {

+            "paramName": "Element",

+            "paramValue": element

+        }];

+        if (ptcname != undefined) {

+            request.params.push({

+                "paramName": "PTCName",

+                "paramValue": ptcname

+            })

+        }

+

+        for (var i = 0; i < params.length; ++i) {

+            request.params.push({

+                "paramName": "ParamName",

+                "paramValue": params[i].paramName

+            });

+            request.params.push({

+                "paramName": "ParamValue",

+                "paramValue": params[i].paramValue

+            });

+        }

+    }

+

+    this.isValidToAddRequest = v_requestBuilder.isValidToAddRequest;

+    this.isValidToCreateRequest = v_requestBuilder.isValidToCreateRequest;

+    this.isValidToMoveRequest = v_requestBuilder.isValidToMoveRequest;

+

+    this.moveRequest = function(p_fromPath, p_toPath, p_position) {

+        v_requestBuilder.moveRequest(p_fromPath, p_toPath, p_position);

+        v_parent.setupChanged("Request changed");

+    };

+

+    this.deleteRequest = function(data) {

+        v_requestBuilder.deleteRequest(data);

+        v_parent.setupChanged("Request changed");

+    };

+

+    this.getRequest = v_requestBuilder.getRequest;

+    this.getRequestFromPath = v_requestBuilder.getRequestFromPath;

+    this.getRequestCopy = v_requestBuilder.getRequestCopy;

+

+    ///////////////////// FUNCTIONS FOR FILTER EDITING /////////////////////

+

+    this.getFilterPart = v_requestBuilder.getFilterPart;

+    this.getFilterPartCopy = v_requestBuilder.getFilterPartCopy;

+    this.addFilterPart = function(p_requestPath, p_filterPath, p_paramName) {

+        v_requestBuilder.addFilterPart(p_requestPath, p_filterPath, p_paramName);

+        v_parent.setupChanged("Filter changed");

+    };

+    this.deleteFilterPart = function(p_requestPath, p_filterPath) {

+        v_requestBuilder.deleteFilterPart(p_requestPath, p_filterPath);

+        v_parent.setupChanged("Filter changed");

+    };

+    this.convertFilterPartToRequest = function(p_requestPath, p_filterPath, p_helpPath) {

+        v_requestBuilder.convertFilterPartToRequest(p_requestPath, p_filterPath, p_helpPath);

+        v_parent.setupChanged("Filter changed");

+    };

+    this.convertFilterPartToDataValue = function(p_requestPath, p_filterPath, p_newValue) {

+        v_requestBuilder.convertFilterPartToDataValue(p_requestPath, p_filterPath, p_newValue);

+        v_parent.setupChanged("Filter changed");

+    };

+    this.isValidToConvertFilterToRequest = v_requestBuilder.isValidToConvertFilterToRequest;

+    this.changeParamNameOfFilterRequest = function(p_requestPath, p_filterPath, p_paramName) {

+        v_requestBuilder.changeParamNameOfFilterRequest(p_requestPath, p_filterPath, p_paramName);

+        v_parent.setupChanged("Filter changed");

+    };

+    this.isValidToAddParamToFilterRequest = v_requestBuilder.isValidToAddParamToFilterRequest;

+    this.convertToDataElementPresentInFilter = function(p_requestPath, p_filterPath) {

+        var filter = v_requestBuilder.getFilterPart(p_requestPath, p_filterPath);

+        var params = filter.request.params;

+        convertTo(filter.request, "dataElementPresent");

+        for (var i = 0; i < filter.request.params.length; ++i) {

+            if (filter.request.params[i].paramValue.dataValue == undefined) {

+                filter.request.params[i].paramValue = {"dataValue": filter.request.params[i].paramValue};

+            }

+        }

+        v_parent.setupChanged("Filter changed");

+    };

+}

+//# sourceURL=GuiEditor\ViewModels\ViewModel_RequestEditor.js

diff --git a/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_SanityChecker.js b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_SanityChecker.js
new file mode 100644
index 0000000..8b834b6
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_SanityChecker.js
@@ -0,0 +1,350 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_SanityChecker_ViewModel(p_model, p_parent) {
+    "use strict";
+
+    var v_model = p_model;
+    var v_fileHandler = v_model.getFileHandler();
+    var v_parent = p_parent;
+
+    var v_help;
+    var v_request;
+    var v_cache;
+
+    var v_this = this;
+
+    ///////////////////// GENERAL VIEWMODEL FUNCTIONS /////////////////////
+
+    this.init = function(p_callback) {
+        v_cache = {};
+        function jsImported(ok, data) {
+            if (!ok) {
+                alert("Some javascript files could not be imported\n" + JSON.stringify(data, null, 4));
+            }
+            p_callback(true);
+        }
+
+        new MultipleDirectoryListTask([
+                v_model.getAppConfig().lastEditedApp + "/ViewModels",
+                "WebApplications/CustomizableApp/ViewModels",
+                v_model.getAppConfig().lastEditedApp + "/Views",
+                "WebApplications/CustomizableApp/Views"
+            ], v_fileHandler).taskOperation(function(ok, resources) {
+            new JsImportTaskList(resources.jsfiles, v_fileHandler, jsImported).taskOperation();
+        });
+    };
+
+    this.setHelp = function(p_help) {
+        v_help = p_help;
+    };
+
+    this.setSetup = function(p_setup) {
+        v_request = p_setup.request.getData();
+    };
+
+    this.addFile = function(fileName) {
+        v_fileHandler.importJsFile(fileName, function(ok, msg) {
+            if (!ok) {
+                alert("Javascript file invalid, import failed: " + fileName + "\n" + msg);
+            }
+        });
+    };
+
+    ///////////////////// INTERFACE FOR VALIDATION AND GETTING HELP /////////////////////
+
+    this.isValidView = function(view, connectedViewmodels) {
+        var viewClass = view.getClass();
+        if (window[viewClass] != undefined) {
+            // check expected interfaces
+            if (window[viewClass].expectsInterface != undefined) {
+                var expectedInterfaces = window[viewClass].expectsInterface();
+                for (var i = 0; i < connectedViewmodels.length; ++i) {
+                    var viewmodelClass = connectedViewmodels[i].getClass();
+                    if (window[viewmodelClass] != undefined && window[viewmodelClass].providesInterface != undefined) {
+                        var providedInterface = window[viewmodelClass].providesInterface();
+                        var useful = false;
+                        for (var j = 0; j < expectedInterfaces.length; ++j) {
+                            var listToSearch = findMandatoryOrOptional(expectedInterfaces[j]);;
+                            if (listToSearch != undefined && isSubsetOf(listToSearch, providedInterface)) {
+                                expectedInterfaces[j].fulfilled = true;
+                                useful = true;
+                            }
+                        }
+                        if (!useful) {
+                            return "connected viewmodel " + i + " of class " + viewmodelClass + " does not provide an expected interface";
+                        }
+                    }
+                }
+
+                for (var i = 0; i < expectedInterfaces.length; ++i) {
+                    if (!expectedInterfaces[i].fulfilled && expectedInterfaces[i].mandatory != undefined) {
+                        return "an interface is not fulfilled: " + expectedInterfaces[i].mandatory;
+                    }
+                }
+            }
+
+            // chack if custom data is valid
+            if (window[viewClass].getCustomDataSchema != undefined && !oldff) {
+                var validate = new Ajv({}).compile(window[viewClass].getCustomDataSchema());
+                var isValid = validate(view.getCustomData());
+                if (!isValid) {
+                    return "custom data does not match the schema";
+                }
+            }
+        }
+
+        return "";
+    };
+
+    this.isValidViewmodel = function(viewmodel) {
+        var viewmodelClass = viewmodel.getClass();
+        if (window[viewmodelClass] != undefined) {
+            // chack if custom data is valid
+            if (window[viewmodelClass].getCustomDataSchema != undefined && !oldff) {
+                var validate = new Ajv({}).compile(window[viewmodelClass].getCustomDataSchema());
+                var isValid = validate(viewmodel.getCustomData());
+                if (!isValid) {
+                    return "custom data does not match the schema";
+                }
+            }
+            // check request connections
+            if (window[viewmodelClass].expectsConnection != undefined) {
+                var expectedConnections = window[viewmodelClass].expectsConnection();
+                var dataConnections = viewmodel.getDataConnections();
+                var selectionConnections = viewmodel.getSelectionConnections();
+                var connectionsOk = checkRequestToViewmodelConnections(dataConnections, selectionConnections, expectedConnections);
+                if (connectionsOk != "") {
+                    return connectionsOk;
+                }
+            }
+        }
+
+        return "";
+    };
+
+    this.getHelp = function(className) {
+        if (window[className] != undefined && window[className].getHelp != undefined) {
+            return window[className].getHelp();
+        } else {
+            return "No help available for " + className;
+        }
+    };
+
+    this.getCustomDataSchema = function(className) {
+        if (window[className] != undefined && window[className].getCustomDataSchema != undefined) {
+            return window[className].getCustomDataSchema();
+        } else {
+            return undefined;
+        }
+    };
+
+    ///////////////////// PRIVATE FUNCTIONS /////////////////////
+
+    function isSubsetOf(subset, set) {
+        var found = true;
+        for (var j = 0; j < subset.length && found; ++j) {
+            found = set.indexOf(subset[j]) != -1;
+        }
+        return found;
+    }
+
+    function findMandatoryOrOptional(expectedInterfaces) {
+        if (expectedInterfaces.mandatory != undefined) {
+            return expectedInterfaces.mandatory;
+        } else if (expectedInterfaces.optional != undefined) {
+            return expectedInterfaces.optional;
+        } else {
+            return undefined;
+        }
+    }
+
+    function checkRequestToViewmodelConnections(dataConnections, selectionConnections, expectedConnections) {
+        var expectedDataConnections = expectedConnections.dataConnections;
+        if (expectedDataConnections != undefined) {
+            if (expectedDataConnections.length == 0 && dataConnections.length > 0) {
+                return "no data connections expected";
+            }
+
+            for (var i = 0; i < dataConnections.length; ++i) {
+
+                var expectedConnectionIndex = Math.min(i, expectedDataConnections.length - 1);
+                var expectedConnection = expectedDataConnections[expectedConnectionIndex];
+                if (i >= expectedDataConnections.length && expectedConnectionIndex == expectedDataConnections.length - 1 && expectedConnection.multiple !== true) {
+                    return "more data connections detected than expected";
+                }
+
+                var result = checkRequestToViewmodelConnection(dataConnections, selectionConnections, expectedConnection, dataConnections, i, "data connection");
+                if (result != "") {
+                    return result;
+                }
+            }
+
+            if (expectedDataConnections[dataConnections.length] != undefined && (expectedDataConnections[dataConnections.length].optional == undefined || expectedDataConnections[dataConnections.length].optional == false)) {
+                return "missing non optional data connection";
+            }
+        }
+
+        var expectedSelectionConnections = expectedConnections.selectionConnections;
+        if (expectedSelectionConnections != undefined) {
+            if (expectedSelectionConnections.length == 0 && selectionConnections.length > 0) {
+                return "no selection connections expected";
+            }
+
+            for (var i = 0; i < selectionConnections.length; ++i) {
+
+                var expectedConnectionIndex = Math.min(i, expectedSelectionConnections.length - 1);
+                var expectedConnection = expectedSelectionConnections[expectedConnectionIndex];
+                if (i >= expectedDataConnections.length && expectedConnectionIndex == expectedSelectionConnections.length - 1 && expectedConnection.multiple !== true) {
+                    return "more selection connections detected than expected";
+                }
+
+                var result = checkRequestToViewmodelConnection(dataConnections, selectionConnections, expectedConnection, selectionConnections, i, "selection connection");
+                if (result != "") {
+                    return result;
+                }
+
+                if (expectedSelectionConnections[selectionConnections.length] != undefined && (expectedSelectionConnections[selectionConnections.length].optional == undefined || expectedSelectionConnections[selectionConnections.length].optional == false)) {
+                    return "missing non optional selection connection";
+                }
+            }
+        }
+
+        return "";
+    }
+
+    function checkRequestToViewmodelConnection(dataConnections, selectionConnections, expectedConnection, connections, indexOfConnection, connectionType) {
+        if (expectedConnection.childOfDataConnection != undefined) {
+            if (dataConnections[expectedConnection.childOfDataConnection] == undefined || !hasPrefix(connections[indexOfConnection], dataConnections[expectedConnection.childOfDataConnection])) {
+                return connectionType + " " + indexOfConnection + " is not a child of data connection " + expectedConnection.childOfDataConnection;
+            }
+        }
+
+        var request = getRequestFromPath(connections[indexOfConnection]);
+
+        if (expectedConnection.element != undefined && expectedConnection.element != request.getData.element) {
+            return "wrong element found for " + connectionType + " " + indexOfConnection + ", expected " + expectedConnection.element;
+        }
+        if (expectedConnection.source != undefined && expectedConnection.source != request.getData.source) {
+            return "wrong source found for " + connectionType + " " + indexOfConnection + ", expected " + expectedConnection.source;
+        }
+        if (expectedConnection.filter == true && request.getData.filter == undefined) {
+            return "expected a filter for " + connectionType + " " + indexOfConnection;
+        }
+
+        if (expectedConnection.valueType != undefined) {
+            var helpDataElement = getHelpFromRequest(request).dataElement;
+            if (helpDataElement != undefined && expectedConnection.valueType.indexOf(helpDataElement.valueType) == -1) {
+                return "wrong value type for " + connectionType + " " + indexOfConnection + ", expected " + expectedConnection.valueType;
+            }
+        }
+
+        if (
+            expectedConnection.dataElementOfDataConnection != undefined && (
+                dataConnections[expectedConnection.dataElementOfDataConnection] == undefined ||
+                getHelpFromRequest(request).index != getHelpFromRequest(getRequestFromPath(dataConnections[expectedConnection.dataElementOfDataConnection])).index
+            )
+        ) {
+            return connectionType + " " + indexOfConnection + " is not the same element as data connection " + expectedConnection.dataElementOfDataConnection;
+        }
+
+        return "";
+
+    }
+
+    function getRequestFromPath(p_path) {
+        var request = v_request[p_path[0]];
+        for (var i = 1; i < p_path.length; ++i) {
+            request = request.getData.children[p_path[i]];
+        }
+        return request;
+    }
+
+    function hasPrefix(path, prefix) {
+        for (var i = 0; i < prefix.length; ++i) {
+            if (path[i] == undefined || path[i] != prefix[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    function getHelpFromRequest(request) {
+        var requestHash = getRequestHash(request);
+        if (v_cache[requestHash] != undefined) {
+            return v_cache[requestHash];
+        }
+
+        var result;
+        var bestIndex;
+        var bestScore = 0;
+        var source = request.getData.source;
+        for (var i = 0; i < v_help.sources.length; ++i) {
+            if (v_help.sources[i].source == source) {
+                for (var j = 0; j < v_help.sources[i].dataElements.length; ++j) {
+                    var score = isCorrectElementForRequest(v_help.sources[i].dataElements[j].dataElement, request);
+                    if (score > bestScore) {
+                        result = {
+                            "index": j,
+                            "dataElement": v_help.sources[i].dataElements[j].dataElement
+                        };
+                        bestScore = score;
+                    }
+                }
+            }
+        }
+
+        if (bestScore == 0) {
+            result = {
+                "index": -1
+            }
+        }
+
+        v_cache[requestHash] = result;
+        return result;
+    }
+
+    function isCorrectElementForRequest(dataElement, request) {
+        if (dataElement.name != request.getData.element) {
+            return 0;
+        }
+
+        var score = 1;
+        var params = getParamTypes(request);
+        if (dataElement.parameters != undefined) {
+            for (var i = 0; i < dataElement.parameters.length; ++i) {
+                if (dataElement.parameters[i].typeDescriptor != undefined && dataElement.parameters[i].typeDescriptor.reference != undefined && dataElement.parameters[i].typeDescriptor.reference.typeName != undefined) {
+                    if (params.indexOf(dataElement.parameters[i].typeDescriptor.reference.typeName) != -1) {
+                        ++score;
+                    }
+                }
+            }
+        }
+
+        return score;
+    }
+
+    function getRequestHash(request) {
+        var hash = request.getData.source + "." + request.getData.element;
+        var params = getParamTypes(request);
+        for (var i = 0; i < params.length; ++i) {
+            hash += "." + params[i];
+        }
+
+        return hash;
+    }
+
+    function getParamTypes(request) {
+        var params = [];
+        if (request.getData.params != undefined) {
+            for (var i = 0; i < request.getData.params.length; ++i) {
+                params.push(request.getData.params[i].paramName);
+            }
+        }
+        params.sort();
+        return params;
+    }
+}
+//# sourceURL=GuiEditor\ViewModels\ViewModel_SanityChecker.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_UIConfigEditor.js b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_UIConfigEditor.js
new file mode 100644
index 0000000..faa7010
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_UIConfigEditor.js
@@ -0,0 +1,88 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_UIConfigEditor_ViewModel(p_model) {
+    "use strict";
+
+    var v_model = p_model;
+
+    var v_configList = [];
+    var v_schemaPresent;
+    var v_config;
+    var v_schema;
+
+    this.getName = function() {
+        return v_config.getUrl();
+    };
+
+    this.listEditableConfigs = function(callback) {
+        function configsListed(configs) {
+            v_configList = configs;
+            var result = [];
+            for (var i = 0; i < configs.length; ++i) {
+                result.push({
+                    "value" : i,
+                    "text" : configs[i].config
+                });
+            }
+            callback(result);
+        }
+
+        v_model.listEditableConfigs(configsListed);
+    };
+
+    this.loadConfig = function(index, callback) {
+        v_config = new JsonLoader(v_configList[index].config, v_model.getFileHandler(), {});
+        v_schema = new JsonLoader(v_configList[index].schema, v_model.getFileHandler(), {});
+
+        function schemaLoaded(ok, data) {
+            if (ok) {
+                v_schemaPresent = true;
+            } else {
+                v_schemaPresent = false;
+            }
+            callback(true);
+        }
+
+        function configLoaded(ok, data) {
+            if (ok) {
+                v_schema.taskOperation(schemaLoaded);
+            } else {
+                callback(false);
+            }
+        }
+
+        v_config.taskOperation(configLoaded);
+    };
+
+    this.isSchemaPresent = function() {
+        return v_schemaPresent;
+    };
+
+    this.getJSONData = function(callback) {
+        callback(v_config.getData());
+    };
+
+    this.setJSONData = function(data) {
+        v_config.setData(data);
+    };
+
+    this.getSchema = function() {
+        return v_schema.getData();
+    };
+
+    this.getTextData = function(callback) {
+        callback(JSON.stringify(v_config.getData(), null, 4));
+    };
+
+    this.setTextData = function(data) {
+        v_config.setData(JSON.parse(data));
+    };
+
+    this.save = function() {
+        v_config.save();
+    };
+}
+//# sourceURL=GuiEditor\ViewModels\ViewModel_UIConfigEditor.js
diff --git a/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_ViewEditor.js b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_ViewEditor.js
new file mode 100644
index 0000000..f812f44
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_ViewEditor.js
@@ -0,0 +1,210 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_ViewEditor_ViewModel(p_model, p_parent) {

+    "use strict";

+

+    var v_model = p_model;

+    var v_parent = p_parent;

+

+    var v_this = this;

+

+    ///////////////////// GENERAL EDITOR FUNCTIONS /////////////////////

+

+    this.getTreeData = function() {

+        var data = [

+            {"text" : "Viewmodel connections", "children" : []},

+            {"text" : "Child of ...", "children" : []},

+            {"text" : "Parent of ...", "children" : []}

+        ];

+

+        var viewModelIndexes = v_model.getViewModelIndexes();

+        for (var i = 0; i < viewModelIndexes.length; ++i) {

+            data[0].children.push({"text" : "ViewModel " + viewModelIndexes[i]});

+        }

+

+        var childIds = v_model.getChildIds();

+        for (var i = 0; i < childIds.length; ++i) {

+            data[2].children.push({"text" : "Child view " + i});

+        }

+

+        return data;

+    };

+

+    this.getName = function() {

+        var name = v_model.getClassName();

+        if (v_model.getCustomData().name != undefined) {

+            name += " - " + v_model.getCustomData().name;

+        }

+        return name;

+    };

+

+    this.getTooltip = function() {

+        return this.getName() + "\n" + v_parent.getHelp(v_model.getClassName()) + "\nCurrent custom data:\n" + JSON.stringify(v_model.getCustomData(), null, 4);

+    };

+

+    this.matches = function(string) {

+        return JSON.stringify(v_model.getDescriptorCopy()).toLowerCase().indexOf(string) != -1;

+    };

+

+    ///////////////////// GENERAL VIEW AND VIEWMODEL EDITOR FUNCTIONS /////////////////////

+

+    this.getCustomData = v_model.getCustomData;

+    this.setCustomData = function(data) {

+        v_model.setCustomData(data);

+        v_parent.setupChanged("Custom data changed");

+    };

+

+    this.getClass = v_model.getClassName;

+    this.setClass = function(p_class) {

+        v_model.setClass(p_class);

+        var childIds = v_model.getChildIds();

+        for (var i = 0; i < childIds.length; ++i) {

+            renameChildId(i, generateChildId(i));

+        }

+        v_parent.setupChanged("Class changed");

+    };

+

+    this.getCustomDataSchema = function() {

+        return v_parent.getCustomDataSchema(v_model.getClassName());

+    };

+

+    this.isValid = function() {

+        return v_parent.isValidView(v_this);

+    };

+

+    ///////////////////// VIEW EDITOR SPECIFIC FUNCTIONS /////////////////////

+

+    this.addViewModelIndex = function(p_viewModelIndex, p_index) {

+        v_model.addViewModelIndex(p_viewModelIndex, p_index);

+        v_parent.setupChanged("Viewmodel connected");

+    };

+    this.deleteViewModelIndexFromPosition = function(p_index) {

+        v_model.deleteViewModelIndexFromPosition(p_index);

+        v_parent.setupChanged("Viewmodel connection deleted");

+    };

+    this.viewModelDeleted = v_model.viewModelDeleted;

+    this.connectionOrderChanged = function(fromIndex, toIndex) {

+        v_model.connectionOrderChanged(fromIndex, toIndex);

+        v_parent.setupChanged("Connection order changed");

+    };

+

+    this.getViewModelIndexes = v_model.getViewModelIndexes;

+

+    function generateChildId(index) {

+        if (v_model.getParentId() != undefined) {

+            return v_model.getParentId() + "_" + v_model.getClassName() + "_" + index;

+        } else {

+            return v_parent.getViewEditorIndex(v_this) + "_" + v_model.getClassName() + "_" + index;

+        }

+    }

+

+    this.getParentId = v_model.getParentId;

+    this.getChildIds = v_model.getChildIds;

+

+    this.setParentId = function(p_id) {

+        v_model.setParentId(p_id);

+        var childIds = v_model.getChildIds();

+        for (var i = 0; i < childIds.length; ++i) {

+            renameChildId(i, generateChildId(i));

+        }

+        v_parent.setupChanged("Parent id changed");

+    };

+

+    function renameChildId(p_index, p_to) {

+        var origName = v_model.getChildIds()[p_index];

+        v_model.renameChildId(p_index, p_to);

+        v_parent.childRenamed(origName, p_to);

+    }

+

+    function updateChildId(p_index, p_to) {

+        var origName = v_model.getChildIds()[p_index];

+        // we do not actually rename it in this case

+        v_parent.childRenamed(origName, p_to);

+    }

+

+    this.addChildView = function(p_index) {

+        var fromIndex = v_model.getChildIds().length;

+        var id = generateChildId(fromIndex);

+

+        v_model.addChildView(id);

+        v_this.childViewOrderChanged(fromIndex, p_index);

+

+        return generateChildId(p_index);

+    };

+

+    this.removeChildView = function(p_index) {

+        var toIndex = v_model.getChildIds().length - 1;

+

+        var origName = v_model.getChildIds()[toIndex];

+

+        v_this.childViewOrderChanged(p_index, toIndex);

+        v_parent.childRenamed(origName);

+

+        v_model.removeChildView();

+    };

+

+    this.removeAllChildren = function() {

+        var childIds = v_model.getChildIds();

+        for (var i = 0; i < childIds.length; ++i) {

+            v_parent.childRenamed(childIds[i]);

+        }

+    };

+

+    this.childViewOrderChanged = function(fromIndex, toIndex) {

+        if (toIndex < fromIndex) {

+            updateChildId(toIndex, "temp");

+            updateChildId(fromIndex, generateChildId(toIndex));

+            for (var i = fromIndex - 1; i > toIndex; --i) {

+                updateChildId(i, generateChildId(i + 1));

+            }

+            v_parent.childRenamed("temp", generateChildId(toIndex + 1));

+        } else if (fromIndex < toIndex) {

+            updateChildId(toIndex, "temp");

+            updateChildId(fromIndex, generateChildId(toIndex));

+            for (var i = fromIndex + 1; i < toIndex; ++i) {

+                updateChildId(i, generateChildId(i - 1));

+            }

+            v_parent.childRenamed("temp", generateChildId(toIndex - 1));

+        } else {

+            updateChildId(toIndex, generateChildId(toIndex));

+        }

+        v_parent.setupChanged("Connection order changed");

+    };

+

+    this.wouldCreateACycle = function(newParentId) {

+        var childIds = v_model.getChildIds();

+        for (var i = 0; i < childIds.length; ++i) {

+            if (newParentId.startsWith(childIds[i])) {

+                return true;

+            }

+        }

+

+        var currentParentId = v_model.getParentId();

+        if (currentParentId != undefined && getPrefixOfParentId(currentParentId) == getPrefixOfParentId(newParentId)) {

+            return true;

+        }

+

+        return false;

+    };

+

+    function getPrefixOfParentId(parentId) {

+        var index = parentId.lastIndexOf("_");

+        if (index != -1) {

+            return parentId.substr(0, index);

+        } else {

+            return parentId;

+        }

+    }

+

+    this.wouldUseId = function(index) {

+        return generateChildId(index);

+    };

+

+    this.removeConnectedChild = function(parentId) {

+        v_parent.removeConnectedChild(parentId);

+    };

+}

+//# sourceURL=GuiEditor\ViewModels\ViewModel_ViewEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_ViewModelEditor.js b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_ViewModelEditor.js
new file mode 100644
index 0000000..e8fd10a
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/ViewModels/ViewModel_ViewModelEditor.js
@@ -0,0 +1,138 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_ViewModelEditor_ViewModel(p_model, p_parent) {

+    "use strict";

+

+    var v_model = p_model;

+    var v_parent = p_parent;

+

+    var v_this = this;

+

+    ///////////////////// GENERAL EDITOR FUNCTIONS /////////////////////

+

+    this.getTreeData = function() {

+        var data = [{"text" : "View connection point"}, {"text": "Data connections", "children": []}, {"text": "Selection connections", "children": []}];

+        getTreeDataFromLists(data, 1, v_model.getDataConnections(), v_model.getDataConnectionsStr());

+        getTreeDataFromLists(data, 2, v_model.getSelectionConnections(), v_model.getSelectionConnectionsStr());

+        return data;

+    };

+

+    function getTreeDataFromLists(data, index, pathList, strPathList) {

+        for (var i = 0; i < pathList.length; ++i) {

+            var text;

+            if (strPathList[i].lastIndexOf(".") === -1) {

+                text = strPathList[i];

+            } else {

+                text = strPathList[i].substr(strPathList[i].lastIndexOf(".") + 1);

+            }

+            data[index].children.push({"text" : text});

+        }

+    }

+

+	this.getName = function() {

+        var name = v_model.getClassName();

+        if (v_model.getCustomData().name != undefined) {

+            name += " - " + v_model.getCustomData().name;

+        }

+        return name;

+	};

+

+    this.getTooltip = function() {

+        return this.getName() + "\n" + v_parent.getHelp(v_model.getClassName()) + "\nCurrent custom data:\n" + JSON.stringify(v_model.getCustomData(), null, 4);

+    };

+

+    this.matches = function(string) {

+        return JSON.stringify(v_model.getDescriptorCopy()).toLowerCase().indexOf(string) != -1;

+    };

+

+    ///////////////////// GENERAL VIEW AND VIEWMODEL EDITOR FUNCTIONS /////////////////////

+

+    this.getCustomData = v_model.getCustomData;

+    this.setCustomData = function(data) {

+        v_model.setCustomData(data);

+        v_parent.setupChanged("Custom data changed");

+    };

+

+    this.getClass = v_model.getClassName;

+	this.setClass = function(data) {

+        v_model.setClass(data);

+        v_parent.setupChanged("Class changed");

+    };

+

+    this.getCustomDataSchema = function() {

+        return v_parent.getCustomDataSchema(v_model.getClassName());

+    };

+

+    this.isValid = function() {

+        return v_parent.isValidViewmodel(v_this);

+    };

+

+    ///////////////////// VIEWMODEL EDITOR SPECIFIC FUNCTIONS /////////////////////

+

+    this.addDataPath = function(strpath, path, index) {

+        v_model.addDataPath(strpath, path, index);

+        v_parent.setupChanged("Request connection added");

+    };

+

+    this.deleteDataPath = function(data) {

+        v_model.deleteDataPath(data);

+        v_parent.setupChanged("Request connection deleted");

+    };

+

+    this.moveDataPath = function(fromIndex, toIndex) {

+        v_model.moveDataPath(fromIndex, toIndex);

+        v_parent.setupChanged("Connection order changed");

+    };

+

+    this.addSelectionPath = function(strpath, path, index) {

+        v_model.addSelectionPath(strpath, path, index);

+        v_parent.setupChanged("Request connection added");

+    };

+

+    this.deleteSelectionPath = function(data) {

+        v_model.deleteSelectionPath(data);

+        v_parent.setupChanged("Request connection deleted");

+    };

+

+    this.moveSelectionPath = function(fromIndex, toIndex) {

+        v_model.moveSelectionPath(fromIndex, toIndex);

+        v_parent.setupChanged("Connection order changed");

+    };

+

+    this.updateConnections = function(path, amount) {

+        var deleted = [];

+        if (amount === -1) {

+            deleted = v_model.deleteConnectionsWithPrefix(mcopy(path));

+        }

+        v_model.updateConnections(mcopy(path), amount);

+        return deleted;

+    };

+

+    this.pathsMoved = v_model.prefixChanged;

+    this.getDataConnections = v_model.getDataConnections;

+    this.getSelectionConnections = v_model.getSelectionConnections;

+

+    this.getDataPathString = function(index) {

+        return v_model.getDataConnectionsStr()[index];

+    };

+

+    this.getSelectionPathString = function(index) {

+        return v_model.getSelectionConnectionsStr()[index];

+    };

+

+    this.requestRenamed = function(p_path, name) {

+        var paths = v_model.requestRenamed(p_path, name);

+        var toReturn = [];

+        for (var i = 0; i < paths["data"].length; ++i) {

+            toReturn.push([1, paths["data"][i]]);

+        }

+        for (var i = 0; i < paths["selection"].length; ++i) {

+            toReturn.push([2, paths["selection"][i]]);

+        }

+        return toReturn;

+    };

+}

+//# sourceURL=GuiEditor\ViewModels\ViewModel_ViewModelEditor.js

diff --git a/htdocs/WebApplications/GuiEditor/Views/View.css b/htdocs/WebApplications/GuiEditor/Views/View.css
new file mode 100644
index 0000000..05cc72a
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View.css
@@ -0,0 +1,446 @@
+/* Main tabs and title */

+

+#GuiEditor_MainView {

+    height: calc(100% - 45px);

+}

+

+#GuiEditor_Tabs {

+    height: calc(100% - 30px);

+}

+

+#GuiEditor_SetupName {

+    margin-bottom: 4px;

+}

+

+#GuiEditor_SetupName label {

+    font-size: 20px;

+    font-weight: bold;

+    display: inline-block;

+}

+

+#GuiEditor_RequestEditorView,

+#GuiEditor_ViewmodelContentEditor,

+#GuiEditor_ViewContentEditor,

+#GuiEditor_InfoAreaView,

+#GuiEditor_RequestEditorSplit,

+#GuiEditor_ViewmodelContentEditor_Tabs,

+#GuiEditor_ViewContentEditor_Tabs,

+#GuiEditor_UIConfigEditor,

+#GuiEditor_UIConfigEditor_EditorContainer {

+    height: calc(100% - 37px);

+}

+

+/* View setup as text tab */

+

+#GuiEditor_InfoArea {

+    height : 100%;

+    resize: none;

+    width: 100%;

+}

+

+/* Content editors */

+

+#GuiEditor_ViewmodelContentEditor_Tabs > .ui-tabs-panel,

+#GuiEditor_ViewContentEditor_Tabs > .ui-tabs-panel {

+    height: calc(100% - 25px);

+}

+

+#GuiEditor_ViewContentEditor_Tabs > .ui-tabs-panel > div > .ui-tabs-panel {

+    height: calc(100% - 22px);

+}

+

+#GuiEditor_ViewmodelContentEditor_Tabs > .ui-tabs-panel > div,

+#GuiEditor_ViewContentEditor_Tabs > .ui-tabs-panel > div,

+#GuiEditor_ViewContentEditor_Tabs > .ui-tabs-panel > div > .ui-tabs-panel > div {

+    height: 100%;

+}

+

+.file-changed  {

+    color: red !important;

+}

+

+/* Setup editor tab */

+

+#GuiEditor_Tabs .Aligner .ui-resizable-handle {

+    background-color: #aaa;

+    width: 5px;

+}

+

+.GuiEditor_Helpside {

+    width: 20%;

+}

+

+#GuiEditor_HelpTree {

+    width: 100%;

+    height: calc(100% - 26px);

+    overflow: auto;

+}

+

+#GuiEditor_RequestTree {

+    width: 20%;

+    padding-bottom: 100px;

+    background-color: #e5e5e5;

+}

+

+#GuiEditor_Playground {

+    width: 80%;

+    height: 100%;

+    display: inline-block;

+    position: relative;

+    overflow: auto;

+}

+

+/* legend */

+

+#GuiEditor_Legend {

+    position: fixed;

+    bottom: 0px;

+    right: 0px;

+    white-space: nowrap;

+    background-color: #e5e5e5;

+    opacity: 0.75;

+    z-index: 10000;

+    user-select: none;

+    cursor: default;

+}

+

+#GuiEditor_LegendToggle {

+    width: 20px;

+    height: 20px;

+    position: fixed;

+    bottom: 0px;

+    right: 0px;

+    background: #a5a5a5;

+    border-top-left-radius: 100%;

+}

+

+#GuiEditor_LegendToggle:hover {

+    background: #b5b5b5;

+}

+

+#GuiEditor_Legend td:first-child {

+    text-align: center;

+}

+

+.GuiEditor_LegendCategory {

+    text-align: center;

+    font-weight: bold;

+}

+

+/* Coloring and sorting trees */

+

+li > a {

+    box-sizing: border-box;

+}

+

+#GuiEditor_RequestTree li.GuiEditor_NodeWithData > a,

+#GuiEditor_Legend .GuiEditor_NodeWithData {

+    border-left: 2px solid #d5d5d5;

+    border-right: 2px solid #d5d5d5;

+    border-top: 2px solid #d5d5d5;

+    border-bottom: 2px solid #d5d5d5;

+}

+

+#GuiEditor_RequestTree ul > li.GuiEditor_NodeWithSelection > a,

+#GuiEditor_Legend .GuiEditor_NodeWithSelection {

+    border-left: 2px solid red;

+}

+

+#GuiEditor_RequestTree ul > li.GuiEditor_NodeWithFilter > a,

+#GuiEditor_Legend .GuiEditor_NodeWithFilter {

+    border-top: 2px solid #9c5ccc;

+}

+

+#GuiEditor_RequestTree ul > li.GuiEditor_NodeWithRangeFilter > a,

+#GuiEditor_Legend .GuiEditor_NodeWithRangeFilter {

+    border-bottom: 2px solid green;

+}

+

+#GuiEditor_RequestTree ul > li.GuiEditor_NodeWithWritableInfo > a,

+#GuiEditor_Legend .GuiEditor_NodeWithWritableInfo {

+    border-right: 2px solid blue;

+}

+

+#GuiEditor_SortButton {

+    background-color: #c5c5c5;

+    height: 25px;

+    display: inline-block;

+    vertical-align: top;

+}

+

+#GuiEditor_SortButton:hover {

+    background-color: #999;

+    color: white;

+}

+

+#GuiEditor_SortButton[aria-pressed="true"] {

+    background-color: #4CAF50;

+    color: white;

+}

+

+#GuiEditor_HelpSearch {

+    width: calc(100% - 60px);

+    height: 20px;

+    display: inline-block;

+    vertical-align: top;

+}

+

+/* Setup editor's editors */

+

+DIV.GuiEditor_EditorHeader {

+    /*text-align: center;*/

+    cursor: move;

+    overflow: hidden;

+    white-space: nowrap;

+    display: block;

+    height: 16px;

+}

+

+DIV.GuiEditor_ViewmodelEditor DIV.GuiEditor_EditorHeader,

+.GuiEditor_ViewmodelEditorLegend {

+    background-color: #5c9ccc;

+}

+

+DIV.GuiEditor_ViewEditor DIV.GuiEditor_EditorHeader,

+.GuiEditor_ViewEditorLegend {

+    background-color: #5ccc9c;

+}

+

+DIV.GuiEditor_HtmlEditor DIV.GuiEditor_EditorHeader,

+.GuiEditor_HtmlEditorLegend {

+    background-color: #9ccc5c;

+}

+

+DIV.GuiEditor_ImportEditor DIV.GuiEditor_EditorHeader,

+.GuiEditor_ImportEditorLegend {

+    background-color: #cc9c5c;

+}

+

+DIV.GuiEditor_FilterEditor DIV.GuiEditor_EditorHeader,

+.GuiEditor_FilterEditorLegend {

+    background-color: #9c5ccc;

+}

+

+label.GuiEditor_HtmlEditorHeaderLabel,

+label.GuiEditor_ViewEditorHeaderLabel,

+label.GuiEditor_ViewmodelEditorHeaderLabel,

+label.GuiEditor_ImportEditorHeaderLabel,

+label.GuiEditor_FilterEditorHeaderLabel {

+    cursor: move;

+    height: 100%;

+    display: inline-block;

+    padding: 0px 4px;

+    white-space: nowrap;

+    overflow: hidden;

+    vertical-align: top;

+    font-size: 10px;

+}

+

+label.GuiEditor_HtmlEditorHeaderLabel {

+	/* 3 buttons, 2 35px, 1 20px, + 3*2 * 1 px border for the buttons = 96px + 2px for good luck */

+    width: calc(100% - 98px);

+}

+

+label.GuiEditor_ImportEditorHeaderLabel {

+    width: calc(100% - 28px);

+}

+

+label.GuiEditor_ViewEditorHeaderLabel,

+label.GuiEditor_ViewmodelEditorHeaderLabel {

+    /* 2 buttons, 1 35px, 1 20px, 2*2 * 1 px border for the buttons = 59px + 4px for good luck */

+    width: calc(100% - 63px);

+}

+

+label.GuiEditor_FilterEditorHeaderLabel {

+    /* 2 buttons, 1 35px, 2 20px, 2*2 * 1 px border for the buttons = 59px + 4px for good luck */

+    width: calc(100% - 83px);

+}

+

+.GuiEditor_ViewmodelEditor, 

+.GuiEditor_ViewEditor,

+.GuiEditor_ImportEditor,

+.GuiEditor_HtmlEditor,

+.GuiEditor_FilterEditor {

+    background-color: #eee;

+    border: 1px solid #aaa;

+    position: absolute;

+    z-index: 800;

+    font-size: 10px;

+    width: auto;

+    height: auto;

+}

+

+button.GuiEditor_EditorButtonLeft,

+button.GuiEditor_EditorButtonRight {

+    background-color: #d66;

+    font-size: 10px;

+    font-weight: bold;

+    width: 35px;

+    height: 100%;

+    display: inline-block;

+    color: #fff;

+    border: 1px solid #ccc;

+    vertical-align: top;

+    padding: 0px;

+}

+

+button.GuiEditor_EditorButtonRight {

+    width: 20px;

+}

+

+button:active.GuiEditor_EditorButtonLeft,

+button:active.GuiEditor_EditorButtonRight {

+    background-color: #f22;

+}

+

+button:hover.GuiEditor_EditorButtonLeft,

+button:hover.GuiEditor_EditorButtonRight {

+    background-color: #e44;

+}

+

+.GuiEditor_Buttonbar {

+    margin: 5px 0 5px 0;

+    width: 100%;

+    height: 22px;

+}

+

+.GuiEditor_Disabled {

+    display: none;

+}

+

+.GuiEditor_Button_Left {

+    float: left;

+    background-color: #ddd;

+    border: 2px solid #ddd;

+    height: 22px;

+}

+

+.GuiEditor_Button_Right {

+    float: right;

+    background-color: #ccc;

+    border: 2px solid #ccc;

+    height: 22px;

+}

+

+.GuiEditor_Button_Left:hover,

+.GuiEditor_Button_Right:hover {

+    background-color: #999;

+    border: 2px solid #999;

+    color: white;

+}

+

+/* 3rd party customization */

+

+.dialog-table TD{

+    font-size: 14pt;

+}

+

+.ui-dialog .ui-state-error {

+    padding: .3em;

+}

+

+.ui-dialog {

+    white-space: nowrap;

+    z-index: 10000 !important;

+}

+

+.ui-widget-overlay {

+    z-index: 9900 !important;

+}

+

+.validateTips {

+    white-space: normal;

+}

+

+.validateSearch {

+    width: 60%;

+}

+

+.validateSearchButton, .validateSearchClear {

+    width: 20%;

+}

+

+.vakata-context {

+    z-index: 4000 !important;

+}

+

+#jstree-marker {

+    z-index: 4000 !important;

+}

+

+.ui-tabs .ui-tabs-nav li {

+    position: relative;

+}

+

+.ui-tabs .ui-tabs-nav .ui-icon-close {

+    cursor: pointer;

+    position: absolute;

+    top: 6px;

+    right: 0px;

+}

+

+.ui-tabs .ui-tabs-nav .ui-tabs-anchor {

+    padding: 6px 20px 6px 6px;

+}

+

+/* Animation for serching */

+

+.GuiEditor_ViewmodelEditor.found > .GuiEditor_EditorHeader > label {

+    animation-name: ViewModel_eph;

+    animation-duration: 2s;

+    animation-iteration-count: infinite;

+}

+

+.GuiEditor_ViewEditor.found > .GuiEditor_EditorHeader > label {

+    animation-name: View_eph;

+    animation-duration: 2s;

+    animation-iteration-count: infinite;

+}

+

+.GuiEditor_ImportEditor.found > .GuiEditor_EditorHeader > label {

+    animation-name: Imports_eph;

+    animation-duration: 2s;

+    animation-iteration-count: infinite;

+}

+

+.GuiEditor_HtmlEditor.found > .GuiEditor_EditorHeader > label {

+    animation-name: Html_eph;

+    animation-duration: 2s;

+    animation-iteration-count: infinite;

+}

+

+#GuiEditor_RequestTree .found {

+    animation-name: Request_eph;

+    animation-duration: 2s;

+    animation-iteration-count: infinite;

+}

+

+@keyframes ViewModel_eph {

+    0%   {background-color: #5c9ccc;}

+    50%  {background-color: green;}

+    100% {background-color: #5c9ccc;}

+}

+

+@keyframes View_eph {

+    0%   {background-color: #5ccc9c;}

+    50%  {background-color: green;}

+    100% {background-color: #5ccc9c;}

+}

+

+@keyframes Imports_eph {

+    0%   {background-color: #cc9c5c;}

+    50%  {background-color: green;}

+    100% {background-color: #cc9c5c;}

+}

+

+@keyframes Html_eph {

+    0%   {background-color: #9ccc5c;}

+    50%  {background-color: green;}

+    100% {background-color: #9ccc5c;}

+}

+

+@keyframes Request_eph {

+    0%   {background-color: #eeeeee;}

+    50%  {background-color: green;}

+    100% {background-color: #eeeeee;}

+}
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/Views/View.html b/htdocs/WebApplications/GuiEditor/Views/View.html
new file mode 100644
index 0000000..369a3c9
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View.html
@@ -0,0 +1,165 @@
+<style id="GuiEditor_WebAppStyle" type="text/css"></style>

+

+<div id="GuiEditor_SetupName">

+    <label id="GuiEditor_AppNameLabel"></label>

+    <label>-</label>

+    <label id="GuiEditor_SetupNameLabel"></label>

+</div>

+

+<div id="GuiEditor_Tabs">

+    <ul>

+        <li><a href="#GuiEditor_RequestEditorView">Setup Editor</a></li>

+        <li><a href="#GuiEditor_InfoAreaView">View Setup as Text</a></li>

+        <li><a href="#GuiEditor_ViewmodelContentEditor">Viewmodel Editor</a></li>

+        <li><a href="#GuiEditor_ViewContentEditor">View Editor</a></li>

+        <li><a href="#GuiEditor_UIConfigEditor">UIConfig Editor</a></li>

+    </ul>

+    

+    <div id="GuiEditor_RequestEditorView" class="tabs">

+        <div id="GuiEditor_Buttonbar" class="GuiEditor_Buttonbar">

+            <button id="GuiEditor_Button_SetApplication" class="GuiEditor_Button_Left">Change Application</button>

+            <button id="GuiEditor_Button_New" class="GuiEditor_Button_Left">New</button>

+            <button id="GuiEditor_Button_Load" class="GuiEditor_Button_Left">Load...</button>

+            <button id="GuiEditor_Button_Save" class="GuiEditor_Button_Left">Save</button>

+            <button id="GuiEditor_Button_SaveAs" class="GuiEditor_Button_Left">Save as...</button>

+            <button id="GuiEditor_Button_History" class="GuiEditor_Button_Left">History</button>

+            

+            <button id="GuiEditor_Button_ExportChartData" class="GuiEditor_Button_Right">Export chart request</button>

+            <button id="GuiEditor_Button_ClearSearch" class="GuiEditor_Button_Right">Clear search</button>

+            <button id="GuiEditor_Button_Search" class="GuiEditor_Button_Right">Search...</button>

+            <button id="GuiEditor_Button_ShowAll" class="GuiEditor_Button_Right">Show all</button>

+            <button id="GuiEditor_Button_AddRequest" class="GuiEditor_Button_Right">Add empty request</button>

+            <button id="GuiEditor_Button_AddImport" class="GuiEditor_Button_Right">Import setup...</button>

+            <button id="GuiEditor_Button_AddView" class="GuiEditor_Button_Right">Add view...</button>

+            <button id="GuiEditor_Button_AddViewmodel" class="GuiEditor_Button_Right">Add viewmodel...</button>

+        </div>

+        <div class="line"></div>

+        <div id="GuiEditor_RequestEditorSplit" class="Aligner">

+            <div class="GuiEditor_Helpside Aligner_Horizontal_Content">

+                <label for="GuiEditor_SortHelpTree" id="GuiEditor_SortButton">Sort</label>

+                <input id="GuiEditor_SortHelpTree" type="checkbox"></input>

+                <input id="GuiEditor_HelpSearch"></input>

+                <div id="GuiEditor_HelpTree"></div>

+            </div>

+            <div id="GuiEditor_Playground" class="Aligner_Horizontal_Content">

+                <div id="GuiEditor_RequestTree"></div>

+                <div id="GuiEditor_Legend">

+                    <div id="GuiEditor_LegendToggle" title="Toggle Legend"></div>

+                    <table id="GuiEditor_LegendTable" class="hidden">

+                        <col width="50px"></col>

+                        <col width="100px"></col>

+                        <tbody>

+                            <tr title="The requests are used to query the DataSource for new data. The requests can have some modifications, like filters and selection.">

+                                <td colspan="2" class="GuiEditor_LegendCategory">Requests</td>

+                            </tr>

+                            <tr title="If the request has a selection, and it returns a lits, only the selected respponse's children will be queried.">

+                                <td class="GuiEditor_NodeWithData GuiEditor_NodeWithSelection"></td>

+                                <td>Selection</td>

+                            </tr>

+                            <tr title="Filters can be used to filter out some responses which do not match the filter. This can be used to return only specific elements in a list or to only query data when some condition is true.">

+                                <td class="GuiEditor_NodeWithData GuiEditor_NodeWithFilter"></td>

+                                <td>Filter</td>

+                            </tr>

+                            <tr title="Range filters are used to query only a part of a list. To control the range filters, specific viewmodels must be used.">

+                                <td class="GuiEditor_NodeWithData GuiEditor_NodeWithRangeFilter"></td>

+                                <td>Range Filter</td>

+                            </tr>

+                            <tr title="The writable info can be used to get writability of an element. This can be used for example to disable a label.">

+                                <td class="GuiEditor_NodeWithData GuiEditor_NodeWithWritableInfo"></td>

+                                <td>Writable Info</td>

+                            </tr>

+                            <tr title="The editor boxes represent the views and viewmodels which are used by the application to display the data.">

+                                <td colspan="2" class="GuiEditor_LegendCategory">Editors</td>

+                            </tr>

+                            <tr title="Viewmodels convert the data received to something that a view can display. Data connections are used to tell a viewmodel which parts of the data to process. Selection connections are used to control the selection of the requests.">

+                                <td class="GuiEditor_ViewmodelEditorLegend"></td>

+                                <td>Viewmodel</td>

+                            </tr>

+                            <tr title="Views represent actual html parts which are displayed on the GUI. Viewmodels supply the views with data and can provide new features for them. Views must be connected to the setup html either directly or through other views, like aligners or tabs.">

+                                <td class="GuiEditor_ViewEditorLegend"></td>

+                                <td>View</td>

+                            </tr>

+                            <tr title="Setups can be imported. This greatly reduces duplication and increases mantainability. Similarly to views, imports must be connected to the setup html or other views. The import can be connected to a request. The request of the imported setup will be inserted below the connected request. This way, it is possible to create generic setups, which do not work by themselvs, but can be imported.">

+                                <td class="GuiEditor_ImportEditorLegend"></td>

+                                <td>Import</td>

+                            </tr>

+                            <tr title="The html editor represent the setup html. Views can connect to elements that have ids.">

+                                <td class="GuiEditor_HtmlEditorLegend"></td>

+                                <td>Html</td>

+                            </tr>

+                            <tr title="The filter editor represents the filter of a request. The filter can be edited similarly to the request: dragging nodes from the help tree or request tree or manually.">

+                                <td class="GuiEditor_FilterEditorLegend"></td>

+                                <td>Filter</td>

+                            </tr>

+                            <tr title="The connections are used to connect the different elements to each other.">

+                                <td colspan="2" class="GuiEditor_LegendCategory">Connections</td>

+                            </tr>

+                            <tr title="A data connection tells a viewmodel which part of the response should it get its data from.">

+                                <td><img src="WebApplications/GuiEditor/Res/legend_connection_request.png"></td>

+                                <td>Data</td>

+                            </tr>

+                            <tr title="Selection connections are used by viewmodels to control the selections of a request.">

+                                <td><img src="WebApplications/GuiEditor/Res/legend_connection_selection.png"></td>

+                                <td>Selection</td>

+                            </tr>

+                            <tr title="Viewmodels connected to views supply them with data and additional capabilities, like sorting and filtering for tables.">

+                                <td><img src="WebApplications/GuiEditor/Res/legend_connection_VM_V.png"></td>

+                                <td>Viewmodel-View</td>

+                            </tr>

+                            <tr title="Views must be connected to other views with view-view connections and eventually to the setup html.">

+                                <td><img src="WebApplications/GuiEditor/Res/legend_connection_V_V.png"></td>

+                                <td>View-View</td>

+                            </tr>

+                            <tr title="All views must be connected to the setup html either directly or through other views.">

+                                <td><img src="WebApplications/GuiEditor/Res/legend_connection_V_html.png"></td>

+                                <td>View-Html</td>

+                            </tr>

+                            <tr title="The request of the imported setup will be inserted below the connected request.">

+                                <td><img src="WebApplications/GuiEditor/Res/legend_connection_import_request.png"></td>

+                                <td>Import request</td>

+                            </tr>

+                        </tbody>

+                    </table>

+                </div>

+            </div>

+        </div>

+    </div>

+    <div id="GuiEditor_InfoAreaView">

+        <textarea id="GuiEditor_InfoArea" spellcheck="false"></textarea>

+    </div>

+    <div id="GuiEditor_ViewmodelContentEditor">

+        <div class="GuiEditor_Buttonbar">

+            <button id="GuiEditor_ViewmodelContentEditor_Button_New" class="GuiEditor_Button_Left">New</button>

+            <button id="GuiEditor_ViewmodelContentEditor_Button_LoadTemplate" class="GuiEditor_Button_Left">Load template</button>

+            <button id="GuiEditor_ViewmodelContentEditor_Button_Load" class="GuiEditor_Button_Left">Load</button>

+            <button id="GuiEditor_ViewmodelContentEditor_Button_Save" class="GuiEditor_Button_Left">Save</button>

+            <button id="GuiEditor_ViewmodelContentEditor_Button_SaveAs" class="GuiEditor_Button_Left">Save as...</button>

+        </div>

+        <div class="line"></div>

+        <div id="GuiEditor_ViewmodelContentEditor_Tabs">

+            <ul>

+            </ul>

+        </div>

+    </div>

+    <div id="GuiEditor_ViewContentEditor">

+        <div class="GuiEditor_Buttonbar">

+            <button id="GuiEditor_ViewContentEditor_Button_New" class="GuiEditor_Button_Left">New</button>

+            <button id="GuiEditor_ViewContentEditor_Button_LoadTemplate" class="GuiEditor_Button_Left">Load template</button>

+            <button id="GuiEditor_ViewContentEditor_Button_Load" class="GuiEditor_Button_Left">Load</button>

+            <button id="GuiEditor_ViewContentEditor_Button_Save" class="GuiEditor_Button_Left">Save</button>

+            <button id="GuiEditor_ViewContentEditor_Button_SaveAs" class="GuiEditor_Button_Left">Save as...</button>

+        </div>

+        <div class="line"></div>

+        <div id="GuiEditor_ViewContentEditor_Tabs">

+            <ul>

+            </ul>

+        </div>

+    </div>

+    <div id="GuiEditor_UIConfigEditor">

+        <div class="GuiEditor_Buttonbar">

+            <button id="GuiEditor_UIConfigEditor_Button_Load" class="GuiEditor_Button_Left">Load</button>

+            <button id="GuiEditor_UIConfigEditor_Button_Save" class="GuiEditor_Button_Left">Save</button>

+        </div>

+        <div id="GuiEditor_UIConfigEditor_EditorContainer"></div>

+    </div>

+</div>

diff --git a/htdocs/WebApplications/GuiEditor/Views/View.js b/htdocs/WebApplications/GuiEditor/Views/View.js
new file mode 100644
index 0000000..99e5772
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View.js
@@ -0,0 +1,403 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_View(p_viewModel, p_parentId, p_viewId) {

+    "use strict";

+

+    var HTML = "WebApplications/GuiEditor/Views/View.html";

+

+    var parentDiv = document.getElementById(p_parentId);

+    var v_parentId = p_parentId;

+    var v_viewId = p_viewId;

+    var v_viewmodel = p_viewModel;

+    var v_this = this;

+

+    var v_requestEditorView = new GuiEditor_RequestEditor_View(v_viewmodel, v_this);

+    var v_viewContentEditorView = new GuiEditor_ViewContentEditor_View(v_viewmodel, "GuiEditor_ViewContentEditor");

+    var v_viewmodelContentEditorView = new GuiEditor_ViewModelContentEditor_View(v_viewmodel, "GuiEditor_ViewmodelContentEditor");

+    var v_uiConfigEditorView = new GuiEditor_JSONConfigEditor_View(v_viewmodel.getUIConfigEditorViewmodel(), "GuiEditor_UIConfigEditor");

+

+    var v_focused_obj;

+

+    ///////////////////// GETTER FOR SUBVIEWS //////////////////////////////

+

+    this.getRequestEditorView = function() {

+        return v_requestEditorView;

+    };

+

+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////

+

+    this.init = function(p_callback) {

+        var mainDiv = document.createElement("div");

+        mainDiv.setAttribute("id", v_viewId);

+        parentDiv.appendChild(mainDiv);

+

+        function htmlLoaded(ok, data) {

+            if (ok) {

+                $("#" + v_viewId).append(data);

+                $('#GuiEditor_Tabs').tabs({

+                    activate: function(ev, ui) {

+                        var oldId = ui.oldPanel.attr("id");

+                        tabClosed(oldId);

+                        var newId = ui.newPanel.attr("id");

+                        tabOpened(newId);

+                    }

+                });

+

+                $("#GuiEditor_WebAppStyle").load("WebApplications/GuiEditor/Views/View.css", function() {

+                    v_this.toggleButtons(false);

+                    p_callback(true);

+                });

+            } else {

+                p_callback(false, "Error loading " + HTML);

+            }

+        }

+

+        v_viewmodel.loadFile(HTML, htmlLoaded);

+    };

+

+    function onWindowResize(event) {

+        if (event.target == window) {

+            $("#GuiEditor_MainView").height(ViewUtils.getSuggestedHeight("GuiEditor_MainView"));

+        }

+    }

+

+    this.applicationCreated = function() {

+        v_requestEditorView.applicationCreated();

+        v_viewContentEditorView.applicationCreated();

+        v_viewmodelContentEditorView.applicationCreated();

+        v_uiConfigEditorView.applicationCreated();

+        $("#GuiEditor_Button_New").on("click", newSetup);

+        $("#GuiEditor_Button_Load").on("click", switchSetup);

+        $("#GuiEditor_Button_Save").on("click", saveSetup);

+        $("#GuiEditor_Button_SaveAs").on("click", saveSetupAs);

+        $("#GuiEditor_Button_Show").on("click", showData);

+        $("#GuiEditor_Button_ExportChartData").on("click", exportChartRequest);

+        $("#GuiEditor_Button_History").on("click", showHistory);

+        $("#GuiEditor_Button_SetApplication").on("click", changeApplication);

+        $(document).on("keydown", keyPressed);

+

+        $(window).on("resize", onWindowResize);

+        $("#GuiEditor_MainView").height(ViewUtils.getSuggestedHeight("GuiEditor_MainView"));

+

+        /* TODO: this works if we add .sortable class to the ul elemens, but do we need it? It would not be here, however.

+        $(".sortable").sortable();

+        $(".sortable").disableSelection();

+        */

+    };

+

+    this.destroy = function() {

+        v_requestEditorView.destroy();

+        $("#" + v_viewId).remove();

+        $(document).off("keydown", keyPressed);

+        $(window).off("resize", onWindowResize);

+    };

+

+    this.unload = function(p_callback) {

+        if (v_viewmodel.isSetupChanged() == true && v_viewmodel.getAppConfig().confirmExit == true) {

+            var exitDialog = new ExitDialog(v_viewId, "GuiEditor_Dialog_Exit", {

+                "header": "Exit GuiEditor",

+                "text": "Do you wish to save changes before leaving?",

+                "callback": function(exit, save) {

+                    if (save) {

+                        saveSetup(function(ok) {

+                            p_callback(exit);

+                        });

+                    } else {

+                        p_callback(exit);

+                    }

+                }

+            });

+            exitDialog.open();

+        } else {

+            p_callback(true);

+        }

+    };

+

+    ///////////////////// EVENT HANDLING FUNCTIONS //////////////////////////////

+

+    function keyPressed(event) {

+        if(event.keyCode === 46 && v_focused_obj != undefined && v_focused_obj.deletePressed != undefined) {

+            v_focused_obj.deletePressed();

+        }

+

+        if(event.keyCode === 83 && event.ctrlKey == true && $("#GuiEditor_Button_Save").attr("disabled") != true) {

+            saveSetup();

+            event.preventDefault();

+            event.stopPropagation();

+        }

+    }

+

+    function tabClosed(id) {

+        if (id == "GuiEditor_RequestEditorView") {

+            $(document).off("keydown", keyPressed);

+        } else if (id == "GuiEditor_UIConfigEditor") {

+            v_uiConfigEditorView.close();

+        }

+    }

+

+    function tabOpened(id) {

+        if (id == "GuiEditor_InfoAreaView") {

+            showData();

+        } else if (id == "GuiEditor_ViewContentEditor") {

+            v_viewContentEditorView.applicationFocused();

+        } else if (id == "GuiEditor_ViewmodelContentEditor") {

+            v_viewmodelContentEditorView.applicationFocused();

+        } else if (id == "GuiEditor_RequestEditorView") {

+            $("#" + v_viewId).on("keydown", keyPressed);

+            $("#" + id).trigger("resize");

+            v_requestEditorView.getEditorContainerView().refreshConnections();

+            v_requestEditorView.getEditorContainerView().validateEditors();

+        } else if (id == "GuiEditor_UIConfigEditor") {

+            v_uiConfigEditorView.refresh();

+        }

+    }

+

+    function newSetup() {

+        v_this.toggleButtons(false);

+        v_viewmodel.newSetup();

+        v_this.updateSetupName();

+        v_focused_obj = undefined;

+    }

+

+    function deleteSetup(value) {

+        var text = "Are you sure your want to delete setup " + value + "?";

+        if (v_viewmodel.isCurrentlyEdited(value)) {

+            text += "<br><b>Warning! This is the currently edited setup<b>";

+        }

+

+        function setupDeleted(ok) {

+            if (!ok) {

+                alert("Failed to delete setup " + value);

+            }

+            v_this.updateSetupName();

+            switchSetup();

+        }

+

+        var dialog = new ConfirmationDialog(v_viewId, "GuiEditor_Dialog_DeleteSetup", {

+            "header": "Delete setup",

+            "text": text,

+            "callback": function() {

+                v_viewmodel.deleteSetup(value, setupDeleted);

+            }

+        });

+        dialog.open();

+    }

+

+    function switchSetup() {

+        function gotSetupName(p_setup) {

+            v_this.toggleButtons(false);

+            v_viewmodel.switchSetup(p_setup,

+                function callback(ok) {

+                    if (!ok) {

+                        alert("Loading setup failed");

+                    }

+                    v_this.updateSetupName();

+                    v_focused_obj = undefined;

+                    v_viewContentEditorView.applicationFocused();

+                }

+            );

+        }

+

+        function optionsArrived(options) {

+            var dialog = new ChoiceDialogWithButton(v_viewId, "GuiEditor_Dialog_LoadSetup", {

+                "header": "Select setup",

+                "text": "Please select a setup from the table below.",

+                "choices": options,

+                "callback": gotSetupName,

+                "buttonHandler": deleteSetup,

+                "buttonText": "X",

+                "buttonStyle": "color: red;",

+                "closeOnButtonPress": true,

+                "searchFunction": v_viewmodel.globalSetupSearch

+            });

+            dialog.open();

+        }

+

+        v_viewmodel.listSetups(optionsArrived);

+    }

+

+    function saveSetup(p_callback) {

+        function setupSaved(ok) {

+            if (!ok) {

+                alert("Failed to save setup " + v_viewmodel.getSetupName());

+            }

+            if (p_callback != undefined && typeof p_callback == "function") {

+                p_callback(ok);

+            }

+            v_this.toggleButtons(true);

+        }

+

+        if (v_viewmodel.isSaveable()) {

+            v_this.toggleButtons(false);

+            v_viewmodel.saveSetup(setupSaved);

+        } else {

+            saveSetupAs(p_callback);

+        }

+    }

+

+    function saveSetupAs(p_callback) {

+        var newSetupName;

+

+        function setupSaved(ok) {

+            if (!ok) {

+                alert("Failed to save setup " + newSetupName);

+            }

+            v_this.updateSetupName();

+            if (p_callback != undefined && typeof p_callback == "function") {

+                p_callback(ok);

+            }

+            v_this.toggleButtons(true);

+        }

+

+        function gotSetupName(value) {

+            newSetupName = value;

+            v_viewmodel.setupExists(newSetupName, function(exists) {

+                if (exists) {

+                    var confirmDialog = new ConfirmationDialog(v_viewId, "GuiEditor_Dialog_OverWrite", {

+                        "header": "Already exists",

+                        "text": "Overwrite directory?",

+                        "callback": function() {

+                            v_this.toggleButtons(false);

+                            v_viewmodel.saveSetupAs(newSetupName, setupSaved);

+                        }

+                    });

+                    confirmDialog.open();

+                } else {

+                    v_this.toggleButtons(false);

+                    v_viewmodel.saveSetupAs(newSetupName, setupSaved);

+                }

+            });

+        }

+

+        var date = new Date();

+        var dialog = new InputDialog(v_viewId, "GuiEditor_Dialog_SaveSetupAs", {

+            "header": "Save Setup As...",

+            "text": "Please enter the name of the setup.<br/>The name should only con&shy;tain upper and lower case eng&shy;lish let&shy;ters, num&shy;bers, under&shy;scores, dots and dashes. The length is also capped at max 32 char&shy;ac&shy;ters.",

+            "defaultValue": "Setup_" + date.getFullYear() + "-" + mpad((date.getMonth() + 1), 2) + "-" + mpad(date.getDate(), 2) + "_" + mpad(date.getHours(), 2) + "-" + mpad(date.getMinutes(), 2) + "-" + mpad(date.getSeconds(), 2),

+            "validator": function(value) {

+                var error = "";

+                var pattern = /^([A-Za-z0-9-_.])+$/;

+                if (!pattern.test(value))

+                    error += "Setup name can only con&shy;tain upper and lower case eng&shy;lish let&shy;ters, num&shy;bers, under&shy;scores, dots and dashes!";

+                if (error.length > 0)

+                  error += "<br/>";

+                if (value.length > 132)

+                    error += "Setup name is too long (max. 132 char&shy;ac&shy;ters allo&shy;wed)!";

+                return error;

+            },

+            "callback": gotSetupName

+        });

+

+        dialog.open();

+    }

+

+    function showData() {

+        $("#GuiEditor_InfoArea").val(v_viewmodel.getJsonRepresentation());

+    }

+

+    function exportChartRequest() {

+        function chartRequestExported() {

+            $("#GuiEditor_Button_ExportChartData").prop("disabled", false).css("color", "");

+        }

+

+        $("#GuiEditor_Button_ExportChartData").prop("disabled", true).css("color", "red");

+        v_viewmodel.exportChartRequest(chartRequestExported);

+    }

+

+    function changeApplication() {

+        function gotApplicationName(p_application) {

+            v_viewmodel.setEditedApp(p_application, function() {

+                newSetup();

+            });

+        }

+

+        function optionsArrived(options) {

+            var dialog = new ChoiceDialog(v_viewId, "GuiEditor_Dialog_SetApplication", {

+                "header": "Select application",

+                "text": "Please select an application from the table below.",

+                "choices": options,

+                "callback": gotApplicationName

+            });

+            dialog.open();

+        }

+

+        v_viewmodel.listEditableApps(optionsArrived);

+    }

+

+    ///////////////////// USEFUL FUNCTION FOR VIEWS //////////////////////////////

+

+    this.toggleButtons = function(on) {

+        $(".GuiEditor_Button_Left").prop("disabled", !on);

+        $(".GuiEditor_Button_Right").prop("disabled", !on);

+    };

+

+    this.setFocusedObj = function(p_object) {

+        if (v_focused_obj != undefined) {

+            v_focused_obj.setDefaultZidx();

+        }

+        if (p_object != undefined) {

+            p_object.setZidx();

+        }

+        v_focused_obj = p_object;

+    };

+

+    this.updateSetupName = function() {

+        var config = v_viewmodel.getAppConfig();

+        if (config.lastEditedApp != undefined) {

+            document.getElementById("GuiEditor_AppNameLabel").innerHTML = config.lastEditedApp;

+        } else {

+            document.getElementById("GuiEditor_AppNameLabel").innerHTML = "... undefined application ...";

+        }

+        if (config.lastEditedSetup != undefined) {

+            document.getElementById("GuiEditor_SetupNameLabel").innerHTML = config.lastEditedSetup;

+        } else {

+            document.getElementById("GuiEditor_SetupNameLabel").innerHTML = "... unsaved setup ...";

+        }

+    };

+

+    ///////////////////// HISTORY //////////////////////////////

+

+    function HistoryElement(index, element) {

+        var v_index = index;

+        this.text = element.text;

+        this.callback = function() {

+            if (v_index != v_viewmodel.getCurrentPositionInHistory()) {

+                v_viewmodel.rewind(v_index);

+            }

+        };

+    }

+

+    function HistoryClass(history) {

+        var v_history = history;

+        this.getMenuElements = function() {

+            var contextItems = [];

+            for (var i = 0; i < v_history.length; ++i) {

+                contextItems.unshift(new HistoryElement(i, v_history[i]));

+            }

+            return contextItems;

+        };

+    }

+

+    function showHistory(event) {

+        v_viewmodel.historyEnabled(false);

+        var history = v_viewmodel.getHistory();

+        var contextMenuViewmodel = new HistoryClass(history);

+        var contextParentId = "GuiEditor_Buttonbar";

+        var contextId = "GuiEditor_History";

+        var customDataForContextMenu = {

+            "offset": $(this).offset()

+        };

+        var contextMenu = new CView_ContextMenu([contextMenuViewmodel], contextId, contextParentId, customDataForContextMenu);

+        contextMenu.applicationCreated();

+        $("#" + contextId).on("remove", function() {

+            v_viewmodel.historyEnabled(true);

+        });

+        $($("#" + contextId + " li")[history.length - v_viewmodel.getCurrentPositionInHistory() - 1]).css("color", "green");

+        $("#" + contextId + " li").css("padding-left", "65px");

+        $("#" + contextId + " li").css("background-color", "rgba(197,197,197,0.9)");

+    }

+}

+//# sourceURL=GuiEditor\Views\View.js

diff --git a/htdocs/WebApplications/GuiEditor/Views/View_BaseContentEditor.js b/htdocs/WebApplications/GuiEditor/Views/View_BaseContentEditor.js
new file mode 100644
index 0000000..c17ef13
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_BaseContentEditor.js
@@ -0,0 +1,208 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_BaseContentEditor_View(p_viewmodel, p_id) {
+
+    var HTML_OF_TAB = '' +
+        '<li>' +
+            '<a {2}href="#{0}">{1}</a>' +
+            '<span class="ui-icon ui-icon-close">Remove Tab</span>' +
+        '</li>';
+
+    var HTML_OF_FILETABS = '<div id="{0}"></div>';
+
+    this.EDITOROPTIONS = {
+        lineNumbers: true,
+        smartIndent: true,
+        indentUnit: 4,
+        lineWrapping: true,
+        foldGutter: true,
+        gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
+        matchBrackets: true,
+        autoCloseBrackets: true,
+        highlightSelectionMatches: true,
+        styleActiveLine: true
+    };
+
+    this.viewmodel = p_viewmodel.getContentEditorViewModel();
+    this.viewId = p_id;
+
+    this.fileTabs;
+
+    var v_this = this;
+
+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////
+
+    this.applicationCreated = function() {
+        v_this.fileTabs = $("#" + v_this.viewId + "_Tabs");
+        v_this.fileTabs.tabs({
+            "active": 0,
+            "activate": function(ev, ui) {
+                v_this.panelActivated(v_this.getPanelOnActivation(ui.newPanel));
+            }
+        });
+
+        // close icon: removing the tab on click
+        v_this.fileTabs.on("click", "span.ui-icon-close", function() {
+            var panelId = $(this).closest("li").remove().attr("aria-controls");
+            $("#" + panelId).remove();
+            v_this.fileTabs.tabs("refresh");
+            v_this.viewmodel.editorClosed(panelId);
+        });
+    };
+
+    ///////////////////// HANDLING TABS AND PANELS //////////////////////////////
+
+    this.getPanelOnActivation = function(panel) {
+        return panel;
+    };
+
+    this.applicationFocused = function() {
+        v_this.panelActivated(v_this.getPanelOnFocus());
+    };
+
+    this.panelActivated = function(panel) {
+        if (panel == undefined || panel.attr("id") == undefined) {
+            return;
+        }
+
+        var id = panel.attr("id");
+        var content = v_this.viewmodel.getContent(panel.attr("id"));
+        var text = content.text;
+        v_this.EDITOROPTIONS.mode = content.mode;
+
+        var codeMirrorInstance;
+
+        if ($("#" + id).data("CodeMirror") == undefined) {
+            panel.append('<div id="' + id + '_Editor"></div>');
+            codeMirrorInstance = CodeMirror(document.getElementById(id + '_Editor'), v_this.EDITOROPTIONS);
+            $("#" + id).data("CodeMirror", codeMirrorInstance);
+            codeMirrorInstance.setSize("100%", "100%");
+
+            codeMirrorInstance.on('changes', function(ev, changes) {
+                if (changes[0].origin != "setValue") {
+                    v_this.viewmodel.setContent(id, codeMirrorInstance.getValue());
+                    v_this.setEdited(true);
+                }
+                // TODO maybe we can check if there is no undo stuff left: doc.historySize()
+            });
+
+        } else {
+            codeMirrorInstance = $("#" + id).data("CodeMirror");
+            codeMirrorInstance.refresh();
+        }
+
+        codeMirrorInstance.setValue(text);
+    };
+
+    this.getPanelOnFocus = function() {
+        v_this.getCurrentlyOpenPanel();
+    };
+
+    this.getCurrentlyOpenPanel = function() {
+        return $("#" + v_this.viewId + "_Tabs").children("div.ui-tabs-panel[aria-hidden='false']");
+    };
+
+    this.setEdited = function(edited, id) {
+        var tab;
+        if (id != undefined) {
+            tab = $('a[href$="' + id + '"]');
+        } else {
+            tab = v_this.getEditedTab();
+        }
+
+        if (edited) {
+            tab.addClass("file-changed");
+        } else {
+            tab.removeClass("file-changed");
+        }
+    };
+
+    this.getEditedTab = function() {
+        return $("#" + v_this.viewId + "_Tabs").find(".ui-tabs-active a");
+    };
+
+    this.changeTabName = function(newName) {
+        $("#" + v_this.viewId + "_Tabs a[href$=" + v_this.getCurrentlyOpenPanel().attr("id") + "]").text(newName);
+    };
+
+    this.getIdOfPanelContainingEditor = function() {
+        return v_this.getCurrentlyOpenPanel().attr("id");
+    };
+
+    ///////////////////// FILE OPERATION HANDLING //////////////////////////////
+
+    this.save = function(saveAsFn) {
+        function saved(ok) {
+            if (!ok) {
+                alert("Failed to save file " + v_this.viewmodel.getFileName(v_this.getIdOfPanelContainingEditor()));
+            } else {
+                v_this.setEdited(false);
+            }
+        }
+
+        var id = v_this.getIdOfPanelContainingEditor();
+        if (id == undefined) {
+            return;
+        } else if (v_this.viewmodel.isSaveable(id)) {
+            v_this.viewmodel.save(id, saved);
+        } else {
+            saveAsFn();
+        }
+    };
+
+    this.saveAs = function(existsFn, saveAsFn, contentType, savedCallback) {
+        var openPanelId = v_this.getCurrentlyOpenPanel().attr("id");
+        if (openPanelId == undefined) {
+            return;
+        }
+
+        var newName;
+
+        function callback(ok, id, existingId) {
+            savedCallback(newName, ok, id, existingId)
+        }
+
+        function gotName(value) {
+            newName = value;
+            existsFn(newName, function(exists) {
+                if (exists) {
+                    var confirmDialog = new ConfirmationDialog(v_this.viewId, "GuiEditor_Dialog_OverWrite", {
+                        "header": "Already exists",
+                        "text": "Overwrite {0}?".format(contentType),
+                        "callback": function() {
+                            saveAsFn(openPanelId, newName, callback);
+                        }
+                    });
+                    confirmDialog.open();
+                } else {
+                    saveAsFn(openPanelId, newName, callback);
+                }
+            });
+        }
+
+        var date = new Date();
+        var dialog = new InputDialog(v_this.viewId, "GuiEditor_Dialog_Save{0}As".format(contentType), {
+            "header": "Save {0} As...".format(contentType),
+            "text": "Please enter the name of the {0}.<br/>The name should only con&shy;tain upper and lower case eng&shy;lish let&shy;ters, num&shy;bers, under&shy;scores, dots and dashes. The length is also capped at max 32 char&shy;ac&shy;ters.".format(contentType),
+            "defaultValue": "{0}_".format(contentType) + date.getFullYear() + "-" + mpad((date.getMonth() + 1), 2) + "-" + mpad(date.getDate(), 2) + "_" + mpad(date.getHours(), 2) + "-" + mpad(date.getMinutes(), 2) + "-" + mpad(date.getSeconds(), 2),
+            "validator": function(value) {
+                var error = "";
+                var pattern = /^([A-Za-z0-9-_.])+$/;
+                if (!pattern.test(value))
+                    error += "{0} name can only con&shy;tain upper and lower case eng&shy;lish let&shy;ters, num&shy;bers, under&shy;scores, dots and dashes!".format(contentType);
+                if (error.length > 0)
+                  error += "<br/>";
+                if (value.length > 32)
+                    error += "{0} name is too long (max. 32 char&shy;ac&shy;ters allo&shy;wed)!".format(contentType);
+                return error;
+            },
+            "callback": gotName
+        });
+
+        dialog.open();
+    };
+}
+//# sourceURL=GuiEditor\Views\View_BaseContentEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/Views/View_BaseEditor.js b/htdocs/WebApplications/GuiEditor/Views/View_BaseEditor.js
new file mode 100644
index 0000000..46f10b1
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_BaseEditor.js
@@ -0,0 +1,445 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_BaseEditor_View(p_viewmodel, p_parentId, p_viewId, p_parent, p_desktopData, p_parentObject) {
+
+    this.viewmodel = p_viewmodel;
+    this.parentId = p_parentId;
+    this.id = p_viewId;
+    this.parent = p_parent;
+    this.jsTreeUtils = new JsTreeUtils();
+
+    this.tree;
+    this.isVisible = true;
+    this.zIndex = 800;
+    this.isEnabled = true;
+
+    var v_parentDiv = document.getElementById(p_parentId);
+    var v_desktopData = p_desktopData;
+    var v_customDataSchema;
+    var v_errorMsg = "";
+
+    var v_this = this;
+    var v_parentObject = p_parentObject;
+
+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////
+
+    this.init = function(callback, className, defaultOffSet) {
+        createMainDiv(className, defaultOffSet);
+        v_this.tree = addTreeDiv("_Tree");
+        v_this.setupCallbacks();
+
+        function treeCreated(ok) {
+            if (!v_this.isVisible) {
+                v_this.tree.slideToggle(0);
+            }
+            callback(ok);
+        }
+
+        v_this.createTree(treeCreated);
+
+        $("#" + v_this.id).on('click', function(){
+            v_this.parent.setFocusedObj(v_parentObject);
+        });
+        $("#" + v_this.id).on('dragstart', function(){
+            v_this.parent.setFocusedObj(v_parentObject);
+        });
+    };
+
+    this.destroy = function() {
+        $("#" + v_this.id).remove();
+    };
+
+    this.setDefaultZidx = function() {
+        $("#" + v_this.id).css("z-index", 800);
+        v_this.zIndex = 800;
+
+        v_this.parent.refreshConnections();
+    };
+
+    this.setZidx = function() {
+        $("#" + v_this.id).css("z-index", 3000);
+        v_this.zIndex = 3000;
+
+        v_this.parent.refreshConnections();
+    };
+
+    ///////////////////// GENERAL EDITOR VIEW FUNCTIONS //////////////////////////////
+
+    this.disabled = function(p_disabled) {
+        if (p_disabled) {
+            $("#" + v_this.id).addClass("GuiEditor_Disabled");
+            if (!v_this.isEnabled) {
+                // already set... this can be used to detect a cycle
+                return true;
+            } else {
+                v_this.isEnabled = false;
+                return false;
+            }
+        } else {
+            $("#" + v_this.id).removeClass("GuiEditor_Disabled");
+            if (v_this.isEnabled) {
+                // already set... this can be used to detect a cycle
+                return true;
+            } else {
+                v_this.isEnabled = true;
+                return false;
+            }
+        }
+    };
+
+    this.isNodeFromTree = function(id) {
+        return v_this.tree.jstree("get_node", id);
+    };
+
+    this.validate = function() {
+        v_errorMsg = v_this.viewmodel.isValid();
+        if (v_errorMsg == "") {
+            $("#" + v_this.id).css("border", "1px solid #aaa");
+        } else {
+            $("#" + v_this.id).css("border", "1px solid red");
+        }
+        v_this.setHeaderText();
+    };
+
+    this.search = function(string) {
+        if (v_this.viewmodel.matches(string)) {
+            $("#" + v_this.id).addClass("found");
+        }
+    };
+
+    ///////////////////// CREATING THE VIEW //////////////////////////////
+
+    this.addButtonToHeader = function(header, id, className, text) {
+        var button = document.createElement("button");
+        button.setAttribute("id", v_this.id + id);
+        button.setAttribute("class", className);
+        var buttonText = document.createTextNode(text);
+        button.appendChild(buttonText);
+        header.appendChild(button);
+    };
+
+    this.fillHeader = function(header) {};
+    this.createTree = function(callback) {callback(true)};
+
+    function addTreeDiv(p_id) {
+        var treediv = document.createElement("div");
+        treediv.setAttribute("id", v_this.id + p_id);
+        document.getElementById(v_this.id).appendChild(treediv);
+        return $("#" + v_this.id + p_id);
+    }
+
+    function createMainDiv(className, defaultOffset) {
+        var div = document.createElement("div");
+        div.setAttribute("id", v_this.id);
+        div.setAttribute("class", className);
+
+        var header = document.createElement("div");
+        header.setAttribute("id", v_this.id + "_Header");
+        header.setAttribute("class", "GuiEditor_EditorHeader");
+
+        v_this.fillHeader(header);
+
+        div.appendChild(header);
+        v_parentDiv.appendChild(div);
+
+        if (v_desktopData.pos == undefined) {
+            v_desktopData.pos = {
+                "top": 0,
+                "left": defaultOffset
+            }
+        }
+
+        var offset = $("#" + v_this.parentId).offset();
+        offset.top += v_desktopData.pos.top;
+        offset.left += v_desktopData.pos.left;
+        $("#" + v_this.id).offset(offset);
+        $("#" + v_this.id).offset(offset);
+
+        if (v_desktopData.visible == undefined) {
+            v_desktopData.visible = true;
+        }
+
+        v_this.isVisible = v_desktopData.visible;
+
+        $("#" + v_this.id).draggable({
+            stop: function(event, ui) {
+                redrawOnDrag(event, ui);
+                document.getElementById(v_this.id).style.height = "auto";
+                document.getElementById(v_this.id).style.width = "auto";
+            },
+            handle: "#" + v_this.id + "_Header",
+            drag: redrawOnDrag,
+            containment: [$("#" + v_this.parentId).offset().left, $("#" + v_this.parentId).offset().top, 20000, 20000]
+        });
+
+        v_this.setHeaderText();
+        changeMinimizeButtonText(v_this.isVisible, v_this.id + "_Button_Minimize");
+    }
+
+    this.setHeaderText = function() {
+        var headerObject = document.getElementById(v_this.id + "_HeaderText");
+        var oldName = headerObject.innerHTML;
+        var newName = v_this.viewmodel.getName();
+        headerObject.innerHTML = newName;
+        if (v_errorMsg == "") {
+            $(headerObject).prop("title", v_this.viewmodel.getTooltip());
+        } else {
+            $(headerObject).prop("title", "WARNING: " + v_errorMsg + "\n\n" + v_this.viewmodel.getTooltip());
+        }
+        if (oldName != newName) {
+            v_this.refreshConnections();
+        }
+        $("#" + v_this.id).width("auto");
+    };
+
+    ///////////////////// HANDLING EVENTS //////////////////////////////
+
+    function redrawOnDrag(event, ui) {
+        v_this.refreshConnections();
+
+        if (event.type == "dragstop") {
+            var parentOffset = $("#" + v_this.parentId).offset();
+            var offset = $("#" + v_this.id).offset();
+            offset.top = offset.top - parentOffset.top + $("#" + v_this.parentId).scrollTop();
+            offset.left = offset.left - parentOffset.left + $("#" + v_this.parentId).scrollLeft();
+            v_desktopData.pos = offset;
+        }
+    }
+
+    this.setupCallbacks = function() {
+        $("#" + v_this.id + "_Button_Edit").on("click", function(event) {
+            // this stops the propagation of the event
+            // when an event occures, it propagates to the parents of the object
+            // we want to focus on the custom data editor, but if we do not stop the propagate, thie editor would also be focused since we listen for the click event on the div
+            event.stopPropagation();
+            editCustomData();
+            return false;
+        });
+
+        $("#" + v_this.id + "_Header").on('contextmenu', function(event) {
+            var list = [
+                {
+                    "text": "copy",
+                    "callback": v_this.copyEditor
+                },
+                {
+                    "text": "change class",
+                    "callback": changeClass
+                },
+                {
+                    "text": "show only this",
+                    "callback": v_this.showOnlyThis
+                },
+                {
+                    "text": "show all",
+                    "callback": v_this.showAll
+                },
+                {
+                    "text": "delete",
+                    "callback": v_this.remove
+                },
+            ];
+
+            v_customDataSchema = v_this.viewmodel.getCustomDataSchema();
+            if (v_customDataSchema != undefined) {
+                list.unshift({
+                    "text": "edit with schema",
+                    "callback": editCustomDataWithSchema
+                });
+            }
+
+            v_this.parent.openContextMenu(list, $("#" + v_this.id).offset());
+
+            event.preventDefault();
+            return false;
+        });
+
+        v_this.setupMinimizedCallback();
+    };
+
+    this.setupMinimizedCallback = function() {
+        $("#" + v_this.id + "_Button_Minimize").on("click", function() {
+            v_this.isVisible = !v_this.isVisible;
+            v_desktopData.visible = v_this.isVisible;
+            v_this.tree.slideToggle("fast", v_this.treeSlid);
+            changeMinimizeButtonText(v_this.isVisible, this.id);
+            $("#" + v_this.id).width("auto");
+        });
+    };
+
+    function changeMinimizeButtonText(visible, button) {
+        if (!visible) {
+            document.getElementById(button).innerHTML = "+";
+        } else {
+            document.getElementById(button).innerHTML = "_";
+        }
+    }
+
+    this.copyEditor = function() {};
+
+    this.treeSlid = function() {
+        v_this.refreshConnections();
+    };
+
+    this.showOnlyThis = function() {
+        v_this.parent.showOnlyThis(v_parentObject);
+    };
+
+    this.showAll = function() {
+        v_this.parent.allDisabled(false);
+        v_this.parent.refreshConnections();
+    };
+
+    this.remove = function() {
+        v_this.destroy();
+        v_this.parent.deleteConnectionsByObject(v_parentObject);
+        v_this.parent.refreshConnections();
+        v_this.editorDeleted();
+    };
+
+    this.editorDeleted = function() {};
+
+    function changeClass() {
+        function callback(param) {
+            v_this.viewmodel.setClass(param);
+            v_this.setHeaderText();
+            v_this.validate();
+        }
+        v_this.getClasses(callback);
+    }
+
+    this.getClasses = function () {};
+
+    this.saveOpenNodes = function() {
+        v_desktopData.openNodes = v_this.jsTreeUtils.findOpenNodes(v_this.tree);
+    };
+
+    this.openNodes = function() {
+        v_this.jsTreeUtils.openNodes(v_this.tree, v_desktopData.openNodes);
+    };
+
+    ///////////////////// EDITING CUSTOM DATA //////////////////////////////
+
+    function editCustomDataWithSchema() {
+        var data = v_this.viewmodel.getCustomData();
+        var offset = $("#" + v_this.id).offset();
+        offset.left += $("#" + v_this.id).width();
+        v_this.parent.editCustomDataWithSchema(v_customDataSchema, data, offset, saveCustomData, v_this);
+    }
+
+    function saveCustomData(data) {
+        v_this.viewmodel.setCustomData(data);
+        v_this.setHeaderText();
+        v_this.validate();
+    }
+
+    function saveCustomDataText(text) {
+        var data = JSON.parse(text);
+        saveCustomData(data);
+    }
+
+    function editCustomData() {
+        var data = v_this.viewmodel.getCustomData();
+        var offset = $("#" + v_this.id).offset();
+        offset.left += $("#" + v_this.id).width();
+        v_this.parent.editCustomData(JSON.stringify(data, null, 4), offset, saveCustomDataText, "Custom data for " + v_this.viewmodel.getClass(), v_this);
+    }
+
+    ///////////////////// HANDLING CONNECTIONS //////////////////////////////
+
+    this.connectionAdded = function(connections, index, endpoint) {
+        for (var i = 0; i < connections.length; ++i) {
+            connections[i].updatePath(index, +1);
+        }
+        connections.splice(index, 0, endpoint);
+        v_this.parent.addEndpoint(endpoint);
+    };
+
+    this.connectionDeleted = function(connections, index) {
+        for (var i = 0; i < connections.length; ++i) {
+            connections[i].updatePath(index, -1);
+        }
+        var endpoint = connections.splice(index, 1)[0];
+        v_this.parent.deleteEndpoint(endpoint);
+    };
+
+    this.connectionMoved = function(connections, fromIndex, toIndex) {
+        if (fromIndex < toIndex) {
+            for (var i = 0; i < connections.length; ++i) {
+                connections[i].updatePath(toIndex + 1, 1);
+            }
+            for (var i = 0; i < connections.length; ++i) {
+                connections[i].setPath(fromIndex, toIndex + 1);
+            }
+            for (var i = 0; i < connections.length; ++i) {
+                connections[i].updatePath(fromIndex, -1);
+            }
+        } else {
+            for (var i = 0; i < connections.length; ++i) {
+                connections[i].updatePath(toIndex, 1);
+            }
+            for (var i = 0; i < connections.length; ++i) {
+                connections[i].setPath(fromIndex + 1, toIndex);
+            }
+            for (var i = 0; i < connections.length; ++i) {
+                connections[i].updatePath(fromIndex + 1, -1);
+            }
+        }
+
+        var endpoint = connections.splice(fromIndex, 1)[0];
+        connections.splice(toIndex, 0, endpoint);
+    };
+
+    this.refreshConnections = function() {
+        v_this.parent.refreshConnections(v_parentObject);
+    };
+
+    this.Endpoint = function(p_path, p_identifier, p_endpointType, p_connectionType, p_options, p_getOffsetOfHtml) {
+
+        this.path = p_path;
+
+        this.getOffset = function() {
+            var htmlObj;
+
+            if (!v_this.isVisible) {
+                var id = v_this.id + "_Header";
+                htmlObj = $("#" + id);
+            } else {
+                var id = v_this.jsTreeUtils.getLastNodeIdFromPath(v_this.tree, this.path);
+                htmlObj = $("#" + id + "_anchor");
+            }
+
+            return p_getOffsetOfHtml(htmlObj);
+        };
+
+        this.getZIndex = function() {
+            return v_this.zIndex + 1;
+        };
+
+        this.isEnabled = function() {
+            return v_this.isEnabled;
+        };
+
+        this.updatePath = function(index, amount) {
+            if (this.path[1] >= index) {
+                this.path[1] += amount;
+            }
+        };
+
+        this.setPath = function(p_from, p_to) {
+            if (this.path[1] == p_from) {
+                this.path[1] = p_to;
+            }
+        };
+
+        this.identifier = p_identifier;
+        this.endpointType = p_endpointType;
+        this.connectionType = p_connectionType;
+        this.object = v_parentObject;
+        this.options = p_options;
+    };
+}
+//# sourceURL=GuiEditor\Views\View_BaseEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/Views/View_Connections.js b/htdocs/WebApplications/GuiEditor/Views/View_Connections.js
new file mode 100644
index 0000000..a8eb9c5
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_Connections.js
@@ -0,0 +1,136 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_Connections_View(p_id, p_parent) {
+    "use strict";
+
+    var v_id = p_id;
+    var v_parent = p_parent;
+
+    var v_connections = [];
+    var v_counter = 0;
+
+    var v_this = this;
+
+    this.destroy = function() {
+        for (var i = 0; i < v_connections.length; ++i) {
+            if (v_connections[i].connection != undefined) {
+                v_connections[i].connection.remove();
+            }
+        }
+
+        v_connections = [];
+        v_counter = 0;
+    };
+
+    this.fullRebuild = function() {
+        v_this.destroy();
+        var objects = v_parent.getObjectsToConnect();
+        for (var i = 0; i < objects.length; ++i) {
+            var endpoints = objects[i].getEndpoints();
+            for (var j = 0; j < endpoints.length; ++j) {
+                var endpoint = endpoints[j];
+                v_this.addEndpoint(endpoint);
+            }
+        }
+    };
+
+    this.addEndpoint = function(endpoint) {
+        var obj = {};
+        v_connections.push(obj);
+
+        var endpointType = endpoint.endpointType;
+        obj[endpointType] = endpoint;
+        var connectionType = endpoint.connectionType;
+        obj["connectionType"] = connectionType;
+
+        if (endpointType == "source") {
+            obj["target"] = v_parent.getEndpoint(connectionType, endpoint.identifier);
+        } else {
+            obj["source"] = v_parent.getEndpoint(connectionType, endpoint.identifier);
+        }
+
+        obj["options"] = endpoint["options"];
+    };
+
+    this.deleteEndpoint = function(endpoint) {
+        var i = 0;
+        while (i < v_connections.length) {
+            if (v_connections[i]["source"] == endpoint || v_connections[i]["target"] == endpoint) {
+                var connection = v_connections.splice(i, 1)[0];
+                if (connection.connection != undefined) {
+                    connection.connection.remove();
+                }
+            } else {
+                ++i;
+            }
+        }
+    };
+
+    this.deleteConnectionsByObject = function(obj) {
+        var i = 0;
+        while (i < v_connections.length) {
+            var found = false;
+            if (v_connections[i]["source"] != undefined && v_connections[i]["source"]["object"] == obj) {
+                found = true;
+            } else if (v_connections[i]["target"] != undefined && v_connections[i]["target"]["object"] == obj) {
+                found = true;
+            }
+
+            if (found) {
+                var connection = v_connections.splice(i, 1)[0];
+                if (connection.connection != undefined) {
+                    connection.connection.remove();
+                }
+            } else {
+                ++i;
+            }
+        }
+    };
+
+    this.refreshConnections = function(obj) {
+        for (var i = 0; i < v_connections.length; ++i) {
+            if (obj != undefined && v_connections[i]["source"] != undefined && v_connections[i]["source"]["object"] != obj && v_connections[i]["target"] != undefined && v_connections[i]["target"]["object"] != obj) {
+                continue;
+            }
+
+            if (v_connections[i].connection != undefined) {
+                v_connections[i].connection.update();
+            } else {
+                v_connections[i].connection = new LineDrawer(
+                    v_id,
+                    v_id + "_svg_" + v_counter,
+                    v_connections[i]["source"],
+                    v_connections[i]["target"],
+                    v_connections[i]["options"]
+                );
+                v_connections[i].connection.init();
+                ++v_counter;
+            }
+        }
+    };
+
+    this.showOnlyThis = function(object) {
+        v_parent.allDisabled(true);
+        object.disabled(false);
+        enable(object, "target", "source");
+        enable(object, "source", "target");
+        v_this.refreshConnections();
+    };
+
+    function enable(p_object, p_endpointTypeOfObject, p_endpointTypeToFind) {
+        for (var i = 0; i < v_connections.length; ++i) {
+            if (v_connections[i][p_endpointTypeOfObject] != undefined && v_connections[i][p_endpointTypeOfObject].object == p_object && v_connections[i][p_endpointTypeToFind] != undefined) {
+                var object = v_connections[i][p_endpointTypeToFind].object;
+                if (object.disabled(false)) {
+                    // we found a parallel path (or very unlikely a cycle)
+                } else {
+                    enable(object, p_endpointTypeOfObject, p_endpointTypeToFind);
+                }
+            }
+        }
+    }
+}
+//# sourceURL=GuiEditor\Views\View_Connections.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/Views/View_EditorContainer.js b/htdocs/WebApplications/GuiEditor/Views/View_EditorContainer.js
new file mode 100644
index 0000000..91104f0
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_EditorContainer.js
@@ -0,0 +1,583 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_EditorContainer_View(p_viewmodel, p_viewId, p_parentView) {

+    "use strict";

+

+    var v_viewId = p_viewId;

+    var v_viewmodel = p_viewmodel.getEditorContainerViewmodel();

+    var v_parentView = p_parentView;

+

+    var v_viewmodelBoxes = [];

+    var v_viewBoxes = [];

+    var v_importBoxes = [];

+    var v_htmlBox;

+

+    var counter = {normal: -1};

+

+    var v_editorId = "GuiEditor_CustomDataEditor";

+    var v_customDataForEditor = {

+        "formatAllowed": true,

+        "closeable": true,

+        "draggable": true,

+        "focusEditorOnOpen": true,

+        "css": {

+            "width": "600px",

+            "height": "506px"

+        }

+    }

+

+    var v_schemaEditorId = "GuiEditor_CustomDataSchemaEditor";

+    var v_customDataForSchemaEditor = {

+        "closeable": true,

+        "draggable": true,

+        "css": {

+            "width": "600px",

+            "height": "506px"

+        },

+        "editorOptions": {

+            "disable_edit_json": true,

+            "keep_oneof_values": false

+        },

+        "headerText": "Edit custom data"

+    }

+

+    var v_lastOpenedBy;

+

+    var v_this = this;

+

+    var v_connectionsView = new GuiEditor_Connections_View(v_viewId, v_this);

+

+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////

+

+    this.applicationCreated = function() {

+        $('#GuiEditor_Button_AddViewmodel').on("click", addViewModel_View);

+        $('#GuiEditor_Button_AddView').on("click", addView_View);

+        $('#GuiEditor_Button_AddImport').on("click", addImport_View);

+        $('#GuiEditor_Button_Search').on("click", function() {

+            $(".found").removeClass("found");

+            var string = prompt("Please enter a string to search for");

+            if (string != undefined) {

+                string = string.toLowerCase();

+                search(string);

+            }

+        });

+        $('#GuiEditor_Button_ClearSearch').on("click", function() {

+            $(".found").removeClass("found");

+        });

+        $("#GuiEditor_LegendToggle").on("click", function() {

+            $("#GuiEditor_LegendTable").toggleClass("hidden");

+        });

+

+        /*

+        $("#GuiEditor_Playground").selectable({

+            "filter": ".ui-draggable",

+            "selected": function(event, ui) {

+                console.log(event, ui);

+            }

+        });

+        */

+    };

+

+    function search(string) {

+        v_parentView.search(string);

+        v_htmlBox.search(string);

+        for (var i = 0; i < v_viewmodelBoxes.length; ++i) {

+            v_viewmodelBoxes[i].search(string);

+        }

+        for (var i = 0; i < v_viewBoxes.length; ++i) {

+            v_viewBoxes[i].search(string);

+        }

+        for (var i = 0; i < v_importBoxes.length; ++i) {

+            v_importBoxes[i].search(string);

+        }

+    }

+

+    this.destroy = function() {

+        for (var i = 0; i < v_viewmodelBoxes.length; ++i) {

+            v_viewmodelBoxes[i].destroy();

+        }

+

+        for (var j = 0; j < v_viewBoxes.length; ++j) {

+            v_viewBoxes[j].destroy();

+        }

+

+        for (var j = 0; j < v_importBoxes.length; ++j) {

+            v_importBoxes[j].destroy();

+        }

+

+        if (v_htmlBox != undefined) {

+            v_htmlBox.destroy();

+            v_htmlBox = undefined;

+        }

+

+        v_viewmodelBoxes = [];

+        v_viewBoxes = [];

+        v_importBoxes = [];

+        counter = {normal: -1};

+

+        v_connectionsView.destroy();

+

+        $("#" + v_editorId).remove();

+        $("#" + v_schemaEditorId).remove();

+    };

+

+    this.setFocusedObj = function(p_object) {

+        v_parentView.setFocusedObj(p_object);

+    };

+

+    ///////////////////// LISTING SETUPS AND CLASSES /////////////////////

+

+    this.getViewClasses = function(p_callback) {

+        function optionsArrived(options) {

+            v_viewmodel.sortOptions(options);

+            var dialog = new ChoiceDialogWithButton(v_viewId, "GuiEditor_Dialog_AddView", {

+                "header": "Select a viewclass",

+                "text": "Select a viewclass",

+                "choices": options,

+                "callback": p_callback,

+                "buttonHandler": showHelp,

+                "buttonText": "?"

+            });

+            dialog.open();

+        }

+

+        v_viewmodel.getViewClassNames(optionsArrived);

+    };

+

+    this.getViewmodelClasses = function(p_callback) {

+        function optionsArrived(options) {

+            v_viewmodel.sortOptions(options);

+            var dialog = new ChoiceDialogWithButton(v_viewId, "GuiEditor_Dialog_AddViewmodel", {

+                "header": "Select a viewmodel class",

+                "text": "Select a viewmodel class",

+                "choices": options,

+                "callback": p_callback,

+                "buttonHandler": showHelp,

+                "buttonText": "?"

+            });

+            dialog.open();

+        }

+

+        v_viewmodel.getViewmodelClassNames(optionsArrived);

+    };

+

+    function showHelp(name) {

+        alert(v_viewmodel.getHelp(name));

+    }

+

+    this.getSetups = function(p_callback) {

+        function optionsArrived(options) {

+            var dialog = new ChoiceDialog(v_viewId, "GuiEditor_Dialog_AddImport", {

+                "header": "Select a setup to import",

+                "text": "Select a setup to import",

+                "choices": options,

+                "callback": p_callback

+            });

+            dialog.open();

+        }

+

+        v_viewmodel.listSetups(optionsArrived);

+    };

+

+    ///////////////////// CREATING EDITORS /////////////////////

+

+    function getCounter(key) {

+        if (key == undefined) {

+            key = "normal";

+        }

+        if (counter[key] == undefined) {

+            counter[key] = -1;

+        }

+        ++counter[key];

+        return counter[key];

+    };

+

+    this.createViewsFromExistingData = function(viewsInitialized) {

+        function viewmodelsArrived(data) {

+            function createViews(viewmodels, desktopData, ClassToInit, listToAppendInto, taskList, classType) {

+                for (var i = 0; i < viewmodels.length; ++i) {

+                    var viewmodel = viewmodels[i];

+                    var idCounter = getCounter(classType);

+                    var view = new ClassToInit(viewmodel, v_viewId, classType + idCounter, v_this, desktopData[i]);

+                    listToAppendInto.push(view);

+                    taskList.push(new GenericTask(view.init));

+                }

+            }

+

+            var taskList = new TaskList([], viewsInitialized);

+

+            createViews(data.view.viewmodels, data.view.desktopData, GuiEditor_ViewEditor_View, v_viewBoxes, taskList, "GuiEditor_ViewEditor_");

+            createViews(data.viewmodel.viewmodels, data.viewmodel.desktopData, GuiEditor_ViewModelEditor_View, v_viewmodelBoxes, taskList, "GuiEditor_ViewmodelEditor_");

+            createViews(data.imports.viewmodels, data.imports.desktopData, GuiEditor_Imports_View, v_importBoxes, taskList, "GuiEditor_ImportEditor_");

+

+            v_htmlBox = new GuiEditor_HtmlEditor_View(v_viewmodel.getHtmlEditorViewmodel(), v_viewId, "GuiEditor_HtmlEditor", v_this);

+            taskList.push(new GenericTask(v_htmlBox.init));

+

+            taskList.taskOperation();

+        }

+

+        v_viewmodel.createViewModelsFromExistingData(viewmodelsArrived);

+    };

+

+    function createViewFromViewmodel(ClassToInit, classType, viewmodel, desktopData, listToAppendInto) {

+        var idCounter = getCounter(classType);

+        var view = new ClassToInit(viewmodel, v_viewId, classType + idCounter, v_this, desktopData);

+        listToAppendInto.push(view);

+        view.init(function() {});

+    }

+

+    function addView(ClassToInit, listToAppendInto, viewmodelFunctionToCall, classType, getClasses) {

+        function viewmodelCreated(viewmodel, desktopData) {

+            createViewFromViewmodel(ClassToInit, classType, viewmodel, desktopData, listToAppendInto);

+        }

+

+        function createViewModel(classname) {

+            viewmodelFunctionToCall(classname, viewmodelCreated);

+        }

+

+        getClasses(createViewModel);

+    }

+

+    function addViewModel_View() {

+        addView(

+            GuiEditor_ViewModelEditor_View,

+            v_viewmodelBoxes,

+            v_viewmodel.createViewModelEditor_ViewModel,

+            "GuiEditor_ViewmodelEditor_",

+            v_this.getViewmodelClasses

+        );

+    }

+

+    function addView_View() {

+        addView(

+            GuiEditor_ViewEditor_View,

+            v_viewBoxes,

+            v_viewmodel.createViewEditor_ViewModel,

+            "GuiEditor_ViewEditor_",

+            v_this.getViewClasses

+        );

+    }

+

+    function addImport_View() {

+        addView(

+            GuiEditor_Imports_View,

+            v_importBoxes,

+            v_viewmodel.createImport_ViewModel,

+            "GuiEditor_ImportEditor_",

+            v_this.getSetups

+        );

+    }

+

+    ///////////////////// COPYING EDITORS /////////////////////

+

+    function copyView(ClassToInit, listToAppendInto, viewmodelFunctionToCall, classType, className, customData) {

+        function viewmodelCreated(viewmodel, desktopData) {

+            createViewFromViewmodel(ClassToInit, classType, viewmodel, desktopData, listToAppendInto);

+        }

+

+        viewmodelFunctionToCall(className, viewmodelCreated, customData);

+    }

+

+    this.copyViewEditor = function(className, customData) {

+        copyView(

+            GuiEditor_ViewEditor_View,

+            v_viewBoxes,

+            v_viewmodel.createViewEditor_ViewModel,

+            "GuiEditor_ViewEditor_",

+            className,

+            customData

+        );

+    };

+

+    this.copyViewmodelEditor = function(className, customData) {

+        copyView(

+            GuiEditor_ViewModelEditor_View,

+            v_viewmodelBoxes,

+            v_viewmodel.createViewModelEditor_ViewModel,

+            "GuiEditor_ViewmodelEditor_",

+            className,

+            customData

+        );

+    };

+

+    ///////////////////// DELETING EDITORS /////////////////////

+

+    this.editorDeleted = function(type, editor) {

+        if (type == "View") {

+            var index = v_viewBoxes.indexOf(editor);

+            v_viewBoxes.splice(index, 1);

+            v_viewmodel.deleteViewEditor_ViewModel(index);

+        } else if (type == "Import") {

+            var index = v_importBoxes.indexOf(editor);

+            v_importBoxes.splice(index, 1);

+            v_viewmodel.deleteImport_ViewModel(index);

+        } else {

+            var index = v_viewmodelBoxes.indexOf(editor);

+

+            for (var i = 0; i < v_viewBoxes.length; ++i) {

+                v_viewBoxes[i].removeViewmodelConnection(index);

+            }

+

+            v_viewmodelBoxes.splice(index, 1);

+            v_viewmodel.deleteViewModelEditor_ViewModel(index);

+        }

+    };

+

+    ///////////////////// HANDLING SUBVIEWS: EDITING CUSTOM DATA AND OPENING CONTEXT MENU /////////////////////

+

+    function createEditor(ClassName, viewmodel, p_id, customData, offset) {

+        var id = p_id;

+        customData.offset = offset;

+

+        var editor = new ClassName([viewmodel], id, v_viewId, customData);

+        editor.applicationCreated();

+        ViewUtils.applyCss(customData, id);

+

+        var editorObj = $("#" + id);

+        editorObj.on('click', function(){

+            v_this.setFocusedObj(editor);

+        });

+        editorObj.on('dragstart', function(){

+            v_this.setFocusedObj(editor);

+        });

+        editor.setDefaultZidx = function() {

+            editorObj.css("z-index" , 2500);

+        };

+        editor.setZidx = function() {

+            editorObj.css("z-index" , 3500);

+        };

+        editorObj.on('remove', function() {

+            v_lastOpenedBy = undefined;

+        });

+

+        v_this.setFocusedObj(editor);

+        editor.refresh(true);

+

+        ViewUtils.jumpToEditor(id);

+    }

+

+    this.editCustomData = function(p_data, p_offset, p_save, p_name, p_callerId) {

+        if (v_lastOpenedBy == p_callerId) {

+            $("#" + v_schemaEditorId).remove();

+            $("#" + v_editorId).remove();

+        } else {

+            $("#" + v_schemaEditorId).remove();

+            $("#" + v_editorId).remove();

+

+            var editorViewmodel = {

+                "getTextData": function(callback) {

+                    callback(p_data)

+                },

+                "setTextData": p_save

+            }

+

+            v_customDataForEditor.headerText = p_name;

+            createEditor(CView_JSONCodeEditor, editorViewmodel, v_editorId, v_customDataForEditor, p_offset);

+            v_lastOpenedBy = p_callerId;

+        }

+    };

+

+    this.editCustomDataWithSchema = function(schema, data, offset, saveCustomData, p_callerId) {

+        if (v_lastOpenedBy == p_callerId) {

+            $("#" + v_schemaEditorId).remove();

+            $("#" + v_editorId).remove();

+        } else {

+            $("#" + v_schemaEditorId).remove();

+            $("#" + v_editorId).remove();

+

+            var editorViewmodel = {

+                "getSchema": function() {

+                    return schema

+                },

+                "getJSONData": function(callback) {

+                    callback(data);

+                },

+                "setJSONData": saveCustomData

+            }

+

+            createEditor(CView_JSONEditor, editorViewmodel, v_schemaEditorId, v_customDataForSchemaEditor, offset);

+            v_lastOpenedBy = p_callerId;

+        }

+    };

+

+    this.openContextMenu = function(list, offset) {

+        var customDataForMenu = {

+            "offset": offset

+        };

+        var id = "GuiEditor_ContextMenu";

+        var contextMenu = new CView_ContextMenu([{

+            "getMenuElements": function() {

+                return list;

+            }

+        }], id, v_viewId, customDataForMenu);

+        contextMenu.applicationCreated();

+        ViewUtils.applyCss(customDataForMenu, id);

+    };

+

+    ///////////////////// HANDLING CONNECTIONS /////////////////////

+

+    this.getObjectsToConnect = function() {

+        var list = [];

+        for (var i = 0; i < v_viewmodelBoxes.length; ++i) {

+            list.push(v_viewmodelBoxes[i]);

+        }

+        for (var i = 0; i < v_viewBoxes.length; ++i) {

+            list.push(v_viewBoxes[i]);

+        }

+        for (var i = 0; i < v_importBoxes.length; ++i) {

+            list.push(v_importBoxes[i]);

+        }

+        list.push(v_htmlBox);

+        return list;

+    };

+

+    this.getEndpoint = function(connectionType, identifier) {

+        if (connectionType == "DR_VM" || connectionType == "SR_VM" || connectionType == "R_I") {

+            return v_parentView.getEndpoint(identifier);

+        } else if (connectionType == "VM_V") {

+            for (var i = 0; i < v_viewmodelBoxes.length; ++i) {

+                var endpoint = v_viewmodelBoxes[i].getEndpoint(identifier);

+                if (endpoint != undefined) {

+                    return endpoint;

+                }

+            }

+        } else if (connectionType == "V_V" || connectionType == "V_HTML") {

+            var list = v_viewBoxes.concat(v_importBoxes);

+            for (var i = 0; i < list.length; ++i) {

+                var endpoint = list[i].getEndpoint(identifier);

+                if (endpoint != undefined) {

+                    return endpoint;

+                }

+            }

+        } else {

+            alert("Unhandled connection type: " + connectionType);

+        }

+    }

+

+    this.allDisabled = function(p_disabled) {

+        for (var i = 0; i < v_viewmodelBoxes.length; ++i) {

+            v_viewmodelBoxes[i].disabled(p_disabled);

+        }

+        for (var i = 0; i < v_viewBoxes.length; ++i) {

+            v_viewBoxes[i].disabled(p_disabled);

+        }

+        for (var i = 0; i < v_importBoxes.length; ++i) {

+            v_importBoxes[i].disabled(p_disabled);

+        }

+    }

+

+    this.refreshConnections = v_connectionsView.refreshConnections;

+    this.deleteConnectionsByObject = v_connectionsView.deleteConnectionsByObject;

+    this.deleteEndpoint = v_connectionsView.deleteEndpoint;

+    this.addEndpoint = v_connectionsView.addEndpoint;

+    this.fullRebuildConnections = v_connectionsView.fullRebuild;

+    this.showOnlyThis = v_connectionsView.showOnlyThis;

+

+    this.getConnectionInformation = function(connectionType, identifier) {

+        if (connectionType == "VM_V") {

+            for (var i = 0; i < v_viewmodelBoxes.length; ++i) {

+                var information = v_viewmodelBoxes[i].getConnectionInformation(identifier);

+                if (information != undefined) {

+                    return information;

+                }

+            }

+        } else if (connectionType == "V_V" || connectionType == "V_HTML") {

+            var list = v_viewBoxes.concat(v_importBoxes);

+            for (var i = 0; i < list.length; ++i) {

+                var information = list[i].getConnectionInformation(identifier);

+                if (information != undefined) {

+                    return information;

+                }

+            }

+        } else {

+            alert("Unhandled connection type: " + connectionType);

+        }

+    };

+

+    ///////////////////// EDITOR MAINTENANCE AFTER CHANGES SOMEWHERE ELSE /////////////////////

+

+    this.updatePaths = function(path, amount) {

+        for (var i = 0; i < v_viewmodelBoxes.length; ++i) {

+            v_viewmodelBoxes[i].updatePaths(mcopy(path), amount);

+        }

+        for (var i = 0; i < v_importBoxes.length; ++i) {

+            v_importBoxes[i].updatePaths(mcopy(path), amount);

+        }

+    };

+

+    this.pathsMoved = function(fromPath, fromPathStr, toPath, toPathStr) {

+        for (var i = 0; i < v_viewmodelBoxes.length; ++i) {

+            v_viewmodelBoxes[i].pathsMoved(mcopy(fromPath), fromPathStr, mcopy(toPath), toPathStr);

+        }

+        for (var i = 0; i < v_importBoxes.length; ++i) {

+            v_importBoxes[i].pathsMoved(mcopy(fromPath), fromPathStr, mcopy(toPath), toPathStr);

+        }

+    };

+

+    this.requestRenamed = function(p_path, name) {

+        for (var i = 0; i < v_viewmodelBoxes.length; ++i) {

+            v_viewmodelBoxes[i].requestRenamed(p_path, name);

+        }

+    };

+

+    this.selectionAddedInRequestTree = function(requestNodeId, parentId) {

+        for (var i = 0; i < v_viewmodelBoxes.length; ++i) {

+            if (v_viewmodelBoxes[i].selectionAddedInRequestTree(requestNodeId, parentId)) {

+                break;

+            }

+        }

+    };

+

+    this.importAddedInRequestTree = function(requestNodeId, parentId) {

+        for (var i = 0; i < v_viewmodelBoxes.length; ++i) {

+            if (v_importBoxes[i].importAddedInRequestTree(requestNodeId, parentId)) {

+                break;

+            }

+        }

+    };

+

+    this.selectionAdded = function(path) {

+        v_parentView.selectionAdded(path);

+    };

+

+    this.removeViewConnection = function(viewIndex, connectionIndex) {

+        if (viewIndex == -1) {

+            v_htmlBox.removeViewConnection(connectionIndex);

+        } else {

+            v_viewBoxes[viewIndex].removeViewConnection(connectionIndex);

+        }

+    };

+

+    ///////////////////// INTER VIEW COMMUNICATION /////////////////////

+

+    this.validateEditors = function() {

+        for (var i = 0; i < v_viewmodelBoxes.length; ++i) {

+            v_viewmodelBoxes[i].validate();

+        }

+

+        for (var i = 0; i < v_viewBoxes.length; ++i) {

+            v_viewBoxes[i].validate();

+        }

+    };

+

+    this.wouldCreateACycle = function(treeId, id) {

+        for (var i = 0; i < v_viewBoxes.length; ++i) {

+            if (v_viewBoxes[i].wouldCreateACycle(treeId, id)) {

+                return true;

+            }

+        }

+        return false;

+    };

+

+    this.getViewmodelIndex = function(obj) {

+        return v_viewmodelBoxes.indexOf(obj);

+    };

+

+    this.getRequestTree = function() {

+        return v_parentView.getRequestTree();

+    };

+}

+//# sourceURL=GuiEditor\Views\View_EditorContainer.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/Views/View_ElementEditor.js b/htdocs/WebApplications/GuiEditor/Views/View_ElementEditor.js
new file mode 100644
index 0000000..bb65f4d
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_ElementEditor.js
@@ -0,0 +1,219 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_ElementEditor_View(p_viewmodel, p_parentId, p_viewId, p_parent) {

+    "use strict";

+

+    var v_id = p_viewId;

+    var v_parentId = p_parentId;

+    var v_editorDiv;

+    var v_open = false;

+

+    var v_parentView = p_parent;

+    var v_viewmodel = p_viewmodel.getRequestEditorViewModel();

+

+    var v_path;

+    var v_request;

+

+    var v_customDataForEditor = {

+        "editorOptions": {

+            "disable_array_reorder": true,

+            "disable_edit_json": true,

+            "disable_collapse": true,

+            "no_additional_properties": true

+        },

+        "css": {

+            "width": "600px",

+            "height": "506px",

+            "z-index": 2000

+        },

+        "closeable": true,

+        "draggable": true,

+        "headerText": "Edit request"

+    }

+

+    var v_viewmodelForJSONEditor;

+    var editor;

+

+    var v_this = this;

+

+    function init() {

+        v_viewmodelForJSONEditor = new ElementEditorViewmodel(v_viewmodel.getRequestCopy(v_path), save);

+        editor = new CView_JSONEditor([v_viewmodelForJSONEditor], v_id, v_parentId, v_customDataForEditor);

+

+        editor.applicationCreated();

+        ViewUtils.applyCss(v_customDataForEditor, v_id);

+

+        v_editorDiv = $("#" + v_id);

+        v_editorDiv.on('click', function(){

+            v_parentView.setFocusedObj(v_this);

+        });

+        v_editorDiv.on('dragstart', function(){

+            v_parentView.setFocusedObj(v_this);

+        });

+        v_editorDiv.on('remove', closed);

+        editor.refresh(true);

+

+        ViewUtils.jumpToEditor(v_id);

+    };

+

+    function closed() {

+        v_viewModel.findSelectionsAndFilters();

+        v_open = false;

+    }

+

+    this.setDefaultZidx = function() {

+        v_editorDiv.css("z-index" , 2500);

+    };

+

+    this.setZidx = function() {

+        v_editorDiv.css("z-index" , 3500);

+    };

+

+    this.deletePressed = function() {

+        v_parentView.deletePressed();

+    };

+

+    this.open = function(p_path, p_offset) {

+        if (v_open) {

+            v_this.close();

+        }

+        v_path = p_path;

+        v_request = v_viewmodel.getRequestFromPath(v_path);

+        v_customDataForEditor.offset = p_offset;

+        init();

+        v_open = true;

+    };

+

+    this.close = function() {

+        if (v_open) {

+            $("#" + v_id).remove();

+        }

+    };

+

+    function save(newRequest) {

+        v_request.getData.source = newRequest.source;

+        v_request.getData.element = newRequest.element;

+        v_parentView.requestRenamed(v_path, newRequest.element);

+        v_request.getData.ptcname = newRequest.ptcname;

+        v_request.getData.params = newRequest.params;

+        v_request.getData.selection = newRequest.selection;

+        v_request.getData.selectionValues = newRequest.selectionValues;

+        v_request.getData.rangeFilter = newRequest.rangeFilter;

+        v_request.getData.writableInfo = newRequest.writableInfo;

+        v_request.getData.timeline = newRequest.timeline;

+

+        v_parentView.selectionOrFilterChanged(v_path, v_request.getData.selection != undefined, v_request.getData.filter != undefined, v_request.getData.rangeFilter != undefined, v_request.getData.writableInfo != undefined);

+    }

+}

+

+function ElementEditorViewmodel(p_data, p_save) {

+    var schema = {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "title": "Edit request",

+        "type": "object",

+        "properties": {

+            "source": {

+                "description": "The source",

+                "type": "string"

+            },

+            "element": {

+                "description": "The element",

+                "type": "string"

+            },

+            "ptcname": {

+                "description": "The ptc name",

+                "type": "string"

+            },

+            "params": {

+                "type": "array",

+                "format": "table",

+                "items": {

+                    "type": "object",

+                    "title": "Parameter",

+                    "properties": {

+                        "paramName" : {

+                            "type" : "string"

+                        },

+                        "paramValue" : {

+                            "type" : "string"

+                        }

+                    },

+                    "additionalProperties": false

+                },

+                "uniqueItems": true

+            },

+            "selection": {

+                "type": "array",

+                "format": "table",

+                "items": {

+                    "type": "integer",

+                    "minimum": "0",

+                    "title": "Selection item"

+                },

+                "uniqueItems": true

+            },

+            "selectionValues": {

+                "type": "array",

+                "format": "table",

+                "items": {

+                    "type": "string",

+                    "title": "Selected value"

+                }

+            },

+            "rangeFilter": {

+                "type": "object",

+                "properties": {

+                    "offset": {

+                        "type": "integer",

+                        "minimum": 0

+                    },

+                    "count": {

+                        "type": "integer",

+                        "minimum": 0

+                    }

+                },

+                "additionalProperties": false

+            },

+            "writableInfo": {

+                "type": "boolean",

+                "default": true

+            },

+            "timeline": {

+                "type": "object",

+                "properties": {

+                    "period": {

+                        "type": "number",

+                        "minimum": 0.0

+                    },

+                    "maxpoints": {

+                        "type": "integer",

+                        "minimum": 1

+                    },

+                    "since": {

+                        "type": "integer",

+                        "minimum": 0

+                    }

+                },

+                "additionalProperties": false,

+                "default": {}

+            }

+        },

+        "required": ["source", "element"]

+    };

+

+    var data = p_data;

+

+    this.getJSONData = function(callback) {

+        callback(data);

+    };

+

+    this.setJSONData = p_save;

+

+    this.getSchema = function() {

+        return schema;

+    };

+}

+//# sourceURL=GuiEditor\Views\View_ElementEditor.js

diff --git a/htdocs/WebApplications/GuiEditor/Views/View_FilterEditor.js b/htdocs/WebApplications/GuiEditor/Views/View_FilterEditor.js
new file mode 100644
index 0000000..b8b1290
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_FilterEditor.js
@@ -0,0 +1,327 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_FilterEditor_View(p_viewmodel, p_parentId, p_viewId, p_parent, p_requestTree, p_helpTree) {
+
+    var v_viewmodel = p_viewmodel.getRequestEditorViewModel();
+    var v_parentId = p_parentId;
+    var v_id = p_viewId;
+    var v_parent = p_parent;
+    var v_editorDiv;
+    var v_open = false;
+
+    var v_tree;
+    var v_requestTree = p_requestTree;
+    var v_helpTree = p_helpTree;
+    var jsTreeUtils = new JsTreeUtils();
+
+    var v_requestPath;
+
+    var v_filterElementEditor = new GuiEditor_FilterElementEditor_View(v_viewmodel, "GuiEditor_Playground", "GuiEditor_FilterElementEditor", this);
+
+    var v_this = this;
+
+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////
+
+    function init() {
+        var html = '' +
+        '<div id="' + v_id + '" class="GuiEditor_FilterEditor">' +
+            '<div id="' + v_id + '_Header' + '" class="GuiEditor_EditorHeader">' +
+                '<button id="' + v_id + '_Button_Add" class="GuiEditor_EditorButtonLeft">Create</button>' +
+                '<label id="' + v_id + '_HeaderText" class="GuiEditor_FilterEditorHeaderLabel">Edit filter</label>' +
+                '<button id="' + v_id + '_Button_Context" class="GuiEditor_EditorButtonRight"><img src="WebApplicationFramework/Res/grip_white.png"></button>' +
+                '<button id="' + v_id + '_Button_Close" class="GuiEditor_EditorButtonRight">X</button>' +
+            '</div>' +
+            '<div id="' + v_id + '_Tree"></div>' +
+        '</div>';
+
+        $("#" + v_parentId).append(html);
+        v_tree = $("#" + v_id + "_Tree");
+        createTree();
+
+        v_editorDiv = $("#" + v_id);
+        v_editorDiv.draggable({
+            stop: function(event, ui) {
+                document.getElementById(v_id).style.height = "auto";
+                document.getElementById(v_id).style.width = "auto";
+            },
+            handle: "#" + v_id + "_Header",
+            containment: [$("#" + v_parentId).offset().left, $("#" + v_parentId).offset().top, 20000, 20000]
+        });
+        v_editorDiv.on('click', function(){
+            v_parent.setFocusedObj(v_this);
+        });
+        v_editorDiv.on('dragstart', function(){
+            v_parent.setFocusedObj(v_this);
+        });
+    };
+
+    this.destroy = function() {
+        v_editorDiv.remove();
+    };
+
+    this.setDefaultZidx = function() {
+        v_editorDiv.css("z-index", 800);
+    };
+
+    this.setFocusedObj = v_parent.setFocusedObj;
+
+    this.setZidx = function() {
+        v_editorDiv.css("z-index", 3000);
+    };
+
+    this.deletePressed = function() {
+        var selected = v_tree.jstree("get_selected")[0];
+        if (selected.length != undefined) {
+            closeEditors();
+
+            var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", selected)).path;
+            filterPath.shift();
+            v_viewmodel.deleteFilterPart(v_requestPath, filterPath);
+            createTree();
+        }
+    };
+
+    ///////////////////// OPENING AND CLOSING THE EDITOR //////////////////////////////
+
+    this.open = function(p_path, p_offset) {
+        if (v_open) {
+            v_this.close();
+        }
+        v_requestPath = p_path;
+        init();
+        $("#" + v_id).offset(p_offset);
+        $("#" + v_id).offset(p_offset);
+        setupCallbacks();
+        v_open = true;
+    };
+
+    this.close = function() {
+        if (v_open) {
+            v_open = false;
+            closeEditors();
+            var request = v_viewmodel.getRequestFromPath(v_requestPath);
+            v_parent.selectionOrFilterChanged(v_requestPath, request.getData.selection != undefined, request.getData.filter != undefined);
+            $("#" + v_id).remove();
+        }
+    };
+
+    function closeEditors() {
+        v_filterElementEditor.close();
+    }
+
+    ///////////////////// CREATING AND REFRESHING THE TREE //////////////////////////////
+
+    function refreshTree() {
+        var data = v_viewmodel.getFilterAsTree(v_requestPath);
+        v_tree.jstree(true).settings.core.data = data;
+        v_tree.jstree("refresh");
+        v_tree.jstree("open_all");
+    }
+
+    function createTree() {
+        var data = v_viewmodel.getFilterAsTree(v_requestPath);
+        v_tree.jstree("destroy");
+        v_tree = v_tree.jstree({
+            "core": {
+                "data": data,
+                "check_callback": function(operation, node, node_parent, node_position, more) {
+                    if (operation === "copy_node" && jsTreeUtils.isNodeFromTree(node, v_helpTree) && !jsTreeUtils.isRoot(node_parent)) {
+                        return dragFromHelpValidate(node.id, node_parent.id);
+                    } else if (operation === "copy_node" && jsTreeUtils.isNodeFromTree(node, v_requestTree) && !jsTreeUtils.isRoot(node_parent)) {
+                        var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", node.id)).path;
+                        return hasPrefix(v_requestPath, path);
+                    } else if (operation === "copy_node") {
+                        return false;
+                    } else {
+                        return true;
+                    }
+                },
+                "multiple": false,
+                "animation": false,
+                "worker": false
+            },
+            "plugins": ["contextmenu", "dnd"],
+            "dnd": {
+                "always_copy": true
+            },
+            "contextmenu": {
+                "items": function($node) {
+                    return {
+                        "Edit": {
+                            "label": "Edit filter",
+                            "action": function(data) {
+                                closeEditors();
+
+                                var offset = data.reference.offset();
+                                offset.left += data.reference.width();
+                                var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.reference)).path;
+                                filterPath.shift();
+                                v_filterElementEditor.open(v_requestPath, filterPath, offset, refreshTree);
+                                v_parent.setFocusedObj(v_filterElementEditor);
+                            },
+                            "separator_after": true
+                        },
+                        "Add": {
+                            "label": "Add param",
+                            "action": function(data) {
+                                closeEditors();
+
+                                var node = v_tree.jstree("get_node", data.reference);
+                                var filterPath = jsTreeUtils.getPath(node).path;
+                                var position = v_tree.jstree("get_children_dom", node).length;
+                                filterPath.shift();
+                                filterPath.push(position);
+                                if (v_viewmodel.isValidToAddParamToFilterRequest(v_requestPath, filterPath)) {
+                                    var paramName = prompt("New param name: ");
+                                    if (paramName != undefined) {
+                                        v_viewmodel.addFilterPart(v_requestPath, filterPath, paramName);
+                                        createTree();
+                                    }
+                                } else {
+                                    alert('Cannot add param to a dataValue');
+                                }
+                            }
+                        },
+                        "RemapTo": {
+                            "label": "Add remapTo",
+                            "action": function(data) {
+                                closeEditors();
+
+                                var node = v_tree.jstree("get_node", data.reference);
+                                var filterPath = jsTreeUtils.getPath(node).path;
+                                var position = v_tree.jstree("get_children_dom", node).length;
+                                filterPath.shift();
+                                filterPath.push(position);
+                                if (v_viewmodel.isValidToAddParamToFilterRequest(v_requestPath, filterPath)) {
+                                    var paramName = "remapTo";
+                                    v_viewmodel.addFilterPart(v_requestPath, filterPath, paramName);
+                                    createTree();
+                                } else {
+                                    alert('Cannot add param to a dataValue');
+                                }
+                            }
+                        },
+                        "Delete": {
+                            "label": "Delete",
+                            "action": function(data) {
+                                closeEditors();
+
+                                var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.reference)).path;
+                                filterPath.shift();
+                                v_viewmodel.deleteFilterPart(v_requestPath, filterPath);
+                                createTree();
+                            },
+                            "separator_after": true
+                        },
+                        "ChangeParamName": {
+                            "label": "Change param name",
+                            "action": function(data) {
+                                closeEditors();
+
+                                var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.reference)).path;
+                                filterPath.shift();
+                                var paramName = prompt("New param name: ");
+                                if (paramName != undefined) {
+                                    v_viewmodel.changeParamNameOfFilterRequest(v_requestPath, filterPath, paramName);
+                                    createTree();
+                                }
+                            }
+                        },
+                        "ConvertToElementPresent": {
+                            "label": "Convert to dataElementPresent",
+                            "action": function(data) {
+                                closeEditors();
+
+                                var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.reference)).path;
+                                filterPath.shift();
+                                if (v_viewmodel.isValidToAddParamToFilterRequest(v_requestPath, filterPath)) {
+                                    v_viewmodel.convertToDataElementPresentInFilter(v_requestPath, filterPath);
+                                }
+                                createTree();
+                            }
+                        }
+                    };
+                },
+                "select_node": true
+            }
+        });
+
+        v_tree.bind("hover_node.jstree", function(e, data) {
+            var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.node.id)).path;
+            filterPath.shift();
+            var string = JSON.stringify(v_viewmodel.getFilterPartCopy(v_requestPath, filterPath), null, 4);
+            $("#" + data.node.id).prop("title", string);
+        });
+
+        v_tree.bind("select_node.jstree", function (e, data) {
+            closeEditors();
+        });
+
+        v_tree.bind("after_close.jstree", function (e, data) {
+            v_tree.jstree("open_all");
+        });
+
+        v_tree.bind("redraw.jstree", function(e, data) {
+            document.getElementById(v_id).style.height = "auto";
+            document.getElementById(v_id).style.width = "auto";
+        });
+
+        v_tree.bind("copy_node.jstree", function(e, data) {
+            if (jsTreeUtils.isNodeFromTree(data.original, v_helpTree)) {
+                helpNodeCopied(data);
+            } else if (jsTreeUtils.isNodeFromTree(data.original, v_requestTree)) {
+                requestNodeCopied(data);
+            }
+        });
+
+        v_tree.bind("ready.jstree", function(e, data) {
+            v_tree.jstree("open_all");
+        });
+    }
+
+    ///////////////////// HANDLING EVENTS //////////////////////////////
+
+    function dragFromHelpValidate(p_helpId, p_filterId) {
+        var helpPath = jsTreeUtils.getPath(v_helpTree.jstree("get_node", p_helpId)).path;
+        var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", p_filterId)).path;
+        filterPath.shift();
+        return v_viewmodel.isValidToConvertFilterToRequest(v_requestPath, filterPath, helpPath)
+    }
+
+    function helpNodeCopied(data) {
+        closeEditors();
+        v_tree.jstree("delete_node", data.node.id);
+        var helpPath = jsTreeUtils.getPath(v_helpTree.jstree("get_node", data.original.id)).path;
+        var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.parent)).path;
+        filterPath.shift();
+        v_viewmodel.convertFilterPartToRequest(v_requestPath, filterPath, helpPath);
+        setTimeout(createTree, 0);
+    }
+
+    function requestNodeCopied(data) {
+        closeEditors();
+        v_tree.jstree("delete_node", data.node.id);
+        var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.original.id)).path;
+        var dataValue = "%Parent" + (path.length - 1) + "%";
+        var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.parent)).path;
+        filterPath.shift();
+        v_viewmodel.convertFilterPartToDataValue(v_requestPath, filterPath, dataValue);
+        setTimeout(createTree, 0);
+    }
+
+    function setupCallbacks() {
+        $('#' + v_id + '_Button_Close').click(v_this.close);
+        $('#' + v_id + '_Button_Context').click(function() {
+            $("#" + jsTreeUtils.getNodeIdFromPath(v_tree, [0]) + " > a").contextmenu();
+        });
+        $('#' + v_id + '_Button_Add').click(function() {
+            closeEditors();
+            v_viewmodel.addFilterPart(v_requestPath, []);
+            createTree();
+        });
+    }
+}
+//# sourceURL=GuiEditor\Views\View_FilterEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/Views/View_FilterElementEditor.js b/htdocs/WebApplications/GuiEditor/Views/View_FilterElementEditor.js
new file mode 100644
index 0000000..5866c5f
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_FilterElementEditor.js
@@ -0,0 +1,180 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_FilterElementEditor_View(p_viewmodel, p_parentId, p_viewId, p_parent) {
+    "use strict";
+
+    var v_id = p_viewId;
+    var v_parentId = p_parentId;
+    var v_editorDiv;
+    var v_open = false;
+
+    var v_parentView = p_parent;
+    var v_viewmodel = p_viewmodel;
+
+    var v_requestPath;
+    var v_filterPath;
+    var v_filter;
+    var v_refresh;
+
+    var v_customDataForEditor = {
+        "editorOptions": {
+            "disable_array_reorder": true,
+            "disable_edit_json": true,
+            "disable_collapse": true,
+            "no_additional_properties": true
+        },
+        "css": {
+            "width": "600px",
+            "height": "506px",
+            "z-index": 2000
+        },
+        "closeable": true,
+        "draggable": true,
+        "headerText": "Edit filter"
+    }
+
+    var v_viewmodelForJSONEditor;
+    var editor;
+
+    var v_this = this;
+
+    function init() {
+        v_viewmodelForJSONEditor = new FilterElementEditorViewmodel(v_viewmodel.getFilterPartCopy(v_requestPath, v_filterPath), save);
+        editor = new CView_JSONEditor([v_viewmodelForJSONEditor], v_id, v_parentId, v_customDataForEditor);
+
+        editor.applicationCreated();
+        ViewUtils.applyCss(v_customDataForEditor, v_id);
+
+        v_editorDiv = $("#" + v_id);
+        v_editorDiv.on('click', function(){
+            v_parentView.setFocusedObj(v_this);
+        });
+        v_editorDiv.on('dragstart', function(){
+            v_parentView.setFocusedObj(v_this);
+        });
+        v_editorDiv.on('remove', closed);
+        editor.refresh(true);
+
+        ViewUtils.jumpToEditor(v_id);
+    };
+
+    function closed() {
+        if (v_open) {
+            v_open = false;
+            v_refresh();
+        }
+    }
+
+    this.setDefaultZidx = function() {
+        v_editorDiv.css("z-index" , 2500);
+    };
+
+    this.setZidx = function() {
+        v_editorDiv.css("z-index" , 3500);
+    };
+
+    this.open = function(p_requestPath, p_filterPath, p_offset, p_refresh) {
+        if (v_open) {
+            v_this.close();
+        }
+        v_requestPath = p_requestPath;
+        v_filterPath = p_filterPath;
+        v_filter = v_viewmodel.getFilterPart(v_requestPath, v_filterPath);
+        v_refresh = p_refresh;
+        v_customDataForEditor.offset = p_offset;
+        init();
+        v_open = true;
+    };
+
+    this.close = function() {
+        if (v_open) {
+            $("#" + v_id).remove();
+        }
+    };
+
+    function save(newFilter) {
+        if (v_open) {
+            if (newFilter.dataValue != undefined) {
+                v_filter.dataValue = newFilter.dataValue;
+                v_filter.request = undefined;
+            } else if (newFilter.request != undefined) {
+                // preserve params
+                if (v_filter.request != undefined) {
+                    v_filter.request.source = newFilter.request.source;
+                    v_filter.request.element = newFilter.request.element;
+                    v_filter.request.ptcname = newFilter.request.ptcname;
+                } else {
+                    v_filter.request = newFilter.request;
+                }
+                v_filter.dataValue = undefined;
+            }
+        }
+    }
+}
+
+function FilterElementEditorViewmodel(p_data, p_save) {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Edit filter",
+        "type": "object",
+        "oneOf": [
+            {
+                "title": "data value",
+                "type": "object",
+                "properties": {
+                    "dataValue": {
+                        "description": "A value",
+                        "type": "string",
+                        "default": "true"
+                    }
+                },
+                "required": ["dataValue"],
+                "additionalProperties": false
+            },
+            {
+                "title": "request",
+                "type": "object",
+                "properties": {
+                    "request": {
+                        "description": "A request that will be converted to a value during the filter evaluation",
+                        "type": "object",
+                        "properties": {
+                            "source": {
+                                "description": "The source",
+                                "type": "string"
+                            },
+                            "element": {
+                                "description": "The element",
+                                "type": "string"
+                            },
+                            "ptcname": {
+                                "description": "The ptc name",
+                                "type": "string"
+                            }
+                        },
+                        "required": ["source", "element"],
+                        "additionalProperties": false
+                    }
+                },
+                "required": ["request"],
+                "additionalProperties": false
+            }
+        ]
+    };
+
+    var data = p_data;
+
+    this.getJSONData = function(callback) {
+        callback(data);
+    };
+
+    this.setJSONData = p_save;
+
+    this.getSchema = function() {
+        return schema;
+    };
+}
+//# sourceURL=GuiEditor\Views\View_FilterElementEditor.js
diff --git a/htdocs/WebApplications/GuiEditor/Views/View_HtmlEditor.js b/htdocs/WebApplications/GuiEditor/Views/View_HtmlEditor.js
new file mode 100644
index 0000000..cd35098
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_HtmlEditor.js
@@ -0,0 +1,375 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_HtmlEditor_View(p_viewModel, p_parentId, p_viewId, p_parent) {
+    "use strict";
+    
+    var base = new GuiEditor_BaseEditor_View(p_viewModel, p_parentId, p_viewId, p_parent, p_viewModel.getDesktopData(), this);
+    
+    var v_this = this;
+    var v_selectedNode = "";
+    
+    var v_ids;
+    
+    var v_htmlEditorId = "GuiEditor_HtmlDataEditor";
+    var v_htmlEditorOpen = false;
+    var v_customDataForHtmlEditor = {
+        "headerText": "Setup html",
+        "closeable": true,
+        "draggable": true,
+        "focusEditorOnOpen": true,
+        "css": {
+            "width": "600px",
+            "height": "506px"
+        }
+    }
+    
+    var v_cssEditorId = "GuiEditor_CssDataEditor";
+    var v_cssEditorOpen = false;
+    var v_customDataForCssEditor = mcopy(v_customDataForHtmlEditor);
+    v_customDataForCssEditor.headerText = "Setup css";
+    
+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////
+    
+    this.init = function(callback) {
+        function baseInitDone(ok) {
+            for (var i = 0; i < v_ids.length; ++i) {
+                if (base.parent.getConnectionInformation("V_HTML", {"parentId": v_ids[i].id, "type": "get"})) {
+                    base.connectionAdded(i, new ViewConnectionEndpoint([i], v_ids[i].id));
+                }
+            }
+            
+            callback(ok);
+        }
+        
+        v_ids = base.viewmodel.collectIds();
+        base.init(baseInitDone, "GuiEditor_HtmlEditor", 970);
+    };
+    
+    this.destroy = function() {
+        base.destroy();
+        $("#" + v_htmlEditorId).off("remove");
+        $("#" + v_htmlEditorId).remove();
+        $("#" + v_cssEditorId).off("remove");
+        $("#" + v_cssEditorId).remove();
+    };
+    
+    this.setDefaultZidx = base.setDefaultZidx;
+    this.setZidx = base.setZidx;
+    this.deletePressed = function() {
+        var node = base.tree.jstree("get_selected");
+        if (node.length > 0) {
+            deleteNode(node);
+        }
+    };
+    
+    ///////////////////// GENERAL EDITOR VIEW FUNCTIONS //////////////////////////////
+    
+    this.disabled = function() {};
+    this.search = base.search;
+    
+    ///////////////////// HTML EDITOR SPECIFIC FUNCTIONS //////////////////////////////
+    
+    this.removeViewConnection = function(connectionIndex) {
+        base.connectionsDeleted(connectionIndex);
+        base.refreshConnections();
+    };
+    
+    ///////////////////// CREATING THE VIEW //////////////////////////////
+    
+    base.fillHeader = function(header) {
+        base.addButtonToHeader(header, "_Button_Html", "GuiEditor_EditorButtonLeft", "HTML");
+        base.addButtonToHeader(header, "_Button_Css", "GuiEditor_EditorButtonLeft", "CSS");
+        var labelText = document.createElement("label");
+        labelText.setAttribute("id", base.id + "_HeaderText");
+        labelText.setAttribute("class", "GuiEditor_HtmlEditorHeaderLabel");
+        header.appendChild(labelText);
+        base.addButtonToHeader(header, "_Button_Minimize", "GuiEditor_EditorButtonRight", " ");
+    };
+
+    base.createTree = function(p_callback) {
+        var data = base.viewmodel.getTreeData();
+        base.tree.jstree("destroy");
+        base.tree.jstree({
+            "core": {
+                "data" : data,
+                "check_callback" : function(operation, node, node_parent, node_position, more) {
+                    if (operation !== "copy_node") {
+                        return true;
+                    } else if (operation === "copy_node" && !base.jsTreeUtils.isRoot(node_parent) && (isAllowedViewConnection(node, node_parent, node_position) || isAllowedImportConnection(node, node_parent, node_position))) {
+                        return true;
+                    } else {
+                        return false;
+                    }
+                },
+                "multiple" : false,
+                "animation": false,
+                "worker": false
+            },
+            "plugins" : ["contextmenu", "dnd"],
+            "contextmenu" : {
+                "items" : function($node) {
+                    return {
+                        "Delete" : {
+                            "label" : "Delete",
+                            "action" : function(data) {
+                                deleteNode(data.reference);
+                            }
+                        }
+                    };
+                },
+                "select_node" : false
+            },
+            'dnd' : {
+                'always_copy' : true
+            }
+        });
+
+        base.tree.bind("copy_node.jstree", function(e, data) {
+            
+            base.tree.jstree("delete_node", data.node.id);
+            base.tree.jstree("delete_node", data.node.id);
+            base.tree.jstree("delete_node", data.node.id);
+            
+            var index = base.jsTreeUtils.getPath(base.tree.jstree("get_node", data.parent)).path[0];            
+            var parentId = v_ids[index].id;
+            
+            if (base.connectionsDeleted(index)) {
+                base.viewmodel.removeChildView(index);
+            }
+            
+            var oldParentId = base.parent.getConnectionInformation("V_HTML", {"treeId": data.original.id, "parentId": parentId, "type": "set"});
+            base.viewmodel.removeConnectedChild(oldParentId);
+            
+            base.connectionAdded(index, new ViewConnectionEndpoint([index], parentId));
+            
+            base.refreshConnections();
+            
+            base.tree.jstree("delete_node", data.node.id);
+            base.tree.jstree("delete_node", data.node.id);
+            
+        });
+
+        base.tree.bind("select_node.jstree", function(e, data) {
+            if (v_selectedNode == data.node.id) {
+                data.instance.deselect_node(data.node);
+                v_selectedNode = "";
+            } else {
+                v_selectedNode = data.node.id;
+            }
+        });
+
+        base.tree.bind("redraw.jstree", function(e, data) {
+            document.getElementById(base.id).style.height = "auto";
+        });
+
+        base.tree.bind("ready.jstree", function(e, data) {
+            p_callback(true);
+        });
+    };
+
+    base.setHeaderText = function() {
+        document.getElementById(base.id + "_HeaderText").innerHTML = base.viewmodel.getName();
+        $("#" + base.id + "_HeaderText").prop("title", base.viewmodel.getName());
+    };
+    
+    ///////////////////// HANDLING EVENTS //////////////////////////////
+    
+    base.setupCallbacks = function() {
+        $("#" + base.id + "_Button_Css").on("click", function(event) {
+            event.stopPropagation();
+            editCss();
+            return false;
+        });
+        
+        $("#" + base.id + "_Button_Html").on("click", function(event) {
+            event.stopPropagation();
+            editHtml();
+            return false;
+        });
+        
+        base.setupMinimizedCallback();
+    };
+    
+    ///////////////////// EDITING HTML AND CSS //////////////////////////////
+    
+    function initEditor(ClassName, viewmodel, p_id, customData) {
+        var id = p_id;
+        
+        var offset = $("#" + base.id).offset();
+        offset.left += $("#" + base.id).width();
+        customData.offset = offset;
+        
+        var editor = new ClassName([viewmodel], id, base.parentId, customData);
+        editor.setDefaultZidx = function() {
+            $("#" + id).css("z-index" , 2500);
+        };
+        editor.setZidx = function() {
+            $("#" + id).css("z-index" , 3500);
+        };
+        editor.applicationCreated();
+        ViewUtils.applyCss(customData, id);
+        $("#" + id).on('click', function(){
+            base.parent.setFocusedObj(editor);
+        });
+        $("#" + id).on('dragstart', function(){
+            base.parent.setFocusedObj(editor);
+        });
+        base.parent.setFocusedObj(editor);
+        editor.refresh(true);
+        
+        ViewUtils.jumpToEditor(id);
+    }
+    
+    function saveCss(text) {
+        base.viewmodel.setCss(text);
+    }
+
+    function editCss() {
+        if (v_cssEditorOpen) {
+            $("#" + v_cssEditorId).remove();
+            v_cssEditorOpen = false;
+        } else {
+            var viewmodel = {
+                "getTextData": base.viewmodel.getCss,
+                "setTextData": saveCss
+            }
+            
+            initEditor(CView_CssEditor, viewmodel, v_cssEditorId, v_customDataForCssEditor);
+            $("#" + v_cssEditorId).on("remove", function() {
+                v_cssEditorOpen = false;
+            });
+            v_cssEditorOpen = true;
+        }
+    }
+    
+    function htmlEditorClosed() {        
+        v_htmlEditorOpen = false;
+        var newIds = base.viewmodel.collectIds();
+        
+        base.createTree(function() {
+            for (var i = 0; i < newIds.length; ++i) {
+                if (newIds[i].prevIndex != -1 && v_ids[newIds[i].prevIndex].endpoint != undefined) {
+                    newIds[i].endpoint = v_ids[newIds[i].prevIndex].endpoint;
+                    newIds[i].endpoint.setPath([i]);
+                    v_ids[newIds[i].prevIndex].endpoint = undefined;
+                }
+            }
+                        
+            for (var i = 0; i < v_ids.length; ++i) {
+                if (v_ids[i].endpoint != undefined) {
+                    base.parent.deleteEndpoint(v_ids[i].endpoint);
+                    base.viewmodel.removeChildViewById(v_ids[i].id);
+                }
+            }
+            
+            v_ids = newIds;
+                        
+            base.refreshConnections();
+        });
+    }
+    
+    function saveHtml(text) {
+        base.viewmodel.setHtml(text);
+    }
+
+    function editHtml() {
+        if (v_htmlEditorOpen) {
+            $("#" + v_htmlEditorId).remove();
+            v_htmlEditorOpen = false;
+        } else {
+            var viewmodel = {
+                "getTextData": base.viewmodel.getHtml,
+                "setTextData": saveHtml
+            };
+            initEditor(CView_HtmlEditor, viewmodel, v_htmlEditorId, v_customDataForHtmlEditor);
+            $("#" + v_htmlEditorId).on("remove", htmlEditorClosed);
+            v_htmlEditorOpen = true;
+        }
+    }
+    
+    ///////////////////// CHECKING OWN EVENTS //////////////////////////////
+    
+    function isAllowedViewConnection(node, parent) {
+        if (node.text === "Child of ..." && !base.jsTreeUtils.isNodeFromTree(node, base.tree) && base.jsTreeUtils.getDepth(parent, base.tree) === 1) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+    
+    function isAllowedImportConnection(node, parent) {
+        if (node.text === "Import into ..." && !base.jsTreeUtils.isNodeFromTree(node, base.tree) && base.jsTreeUtils.getDepth(parent, base.tree) === 1) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+    
+    ///////////////////// HANDLING OWN EVENTS //////////////////////////////
+    
+    function deleteNode(p_data) {
+        var treeNode = base.tree.jstree("get_node", p_data);
+        var jqueryNode = $("#" + treeNode.id);
+        var index = jqueryNode.parent().children().index(jqueryNode[0]);
+        if (base.connectionsDeleted(index)) {
+            base.viewmodel.removeChildView(index);
+        }
+        base.refreshConnections();
+    }
+    
+
+    
+    ///////////////////// HANDLING CONNECTIONS //////////////////////////////
+    
+    base.connectionAdded = function(index, endpoint) {
+        v_ids[index].endpoint = endpoint;
+        base.parent.addEndpoint(endpoint);
+    };
+    
+    base.connectionsDeleted = function(connectionIndex) {
+        if (v_ids[connectionIndex].endpoint != undefined) {
+            base.parent.deleteEndpoint(v_ids[connectionIndex].endpoint);
+            v_ids[connectionIndex].endpoint = undefined;
+            return true;
+        } else {
+            return false;
+        }
+    };
+    
+    function ViewConnectionEndpoint(p_path, p_identifier) {
+        var endpoint = new base.Endpoint(
+            p_path,
+            p_identifier,
+            "target",
+            "V_HTML",
+            {
+                "stroke": "#9ccc5c"
+            },
+            function(htmlObj) {
+                var offset = htmlObj.offset();
+                offset.top += htmlObj.height() / 2;
+                return offset;
+            }
+        );
+        
+        endpoint.setPath = function(path) {
+            endpoint.path = path;
+        }
+        
+        return endpoint;
+    }
+    
+    this.getEndpoints = function() {
+        var list = [];
+        for (var i = 0; i < v_ids.length; ++i) {
+            if (v_ids[i].endpoint != undefined) {
+                list.push(v_ids[i].endpoint);
+            }
+        }
+        return list;
+    };
+}
+//# sourceURL=GuiEditor\Views\View_HtmlEditor.js
diff --git a/htdocs/WebApplications/GuiEditor/Views/View_Imports.js b/htdocs/WebApplications/GuiEditor/Views/View_Imports.js
new file mode 100644
index 0000000..2fae9de
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_Imports.js
@@ -0,0 +1,359 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_Imports_View(p_viewModel, p_parentId, p_viewId, p_parent, p_desktopData) {
+    "use strict";
+
+    var base = new GuiEditor_BaseEditor_View(p_viewModel, p_parentId, p_viewId, p_parent, p_desktopData, this);
+    var v_requestTree = base.parent.getRequestTree();
+    var v_requestConnectionPresent = false;
+    var v_selectedNode;
+
+    var v_this = this;
+
+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////
+
+    this.init = function(callback) {
+        base.init(callback, "GuiEditor_ImportEditor", 800);
+        v_requestConnectionPresent = base.viewmodel.getRequestPath() != undefined;
+    };
+
+    this.destroy = base.destroy;
+    this.setDefaultZidx = base.setDefaultZidx;
+    this.setZidx = base.setZidx;
+    this.deletePressed = function() {
+        var node = base.tree.jstree("get_selected");
+        if (node.length > 0) {
+            deleteNode(node);
+        }
+    };
+
+    ///////////////////// GENERAL EDITOR VIEW FUNCTIONS //////////////////////////////
+
+    this.disabled = base.disabled;
+    this.search = base.search;
+
+    ///////////////////// IMPORT EDITOR SPECIFIC FUNCTIONS //////////////////////////////
+
+    this.updatePaths = function(path, amount) {
+        var connectionRemoved = base.viewmodel.updatePaths(path, amount);
+        if (connectionRemoved) {
+            v_requestConnectionPresent = false;
+            base.parent.deleteEndpoint(requestConnectionEndpoint);
+        }
+    };
+
+    this.pathsMoved = base.viewmodel.pathsMoved;
+
+    this.importAddedInRequestTree = function(requestNodeId, parentId) {
+        var parent = base.tree.jstree("get_node", parentId);
+        if (base.jsTreeUtils.isNodeFromTree(parent, base.tree)) {
+            var data = {
+                "parent": parent,
+                "position": 0,
+                "original": {
+                    "id": requestNodeId
+                }
+            };
+            requestAdded(data, false);
+            return true;
+        } else {
+            return false;
+        }
+    };
+
+    ///////////////////// CREATING THE VIEW //////////////////////////////
+
+    base.fillHeader = function(header) {
+        var labelText = document.createElement("label");
+        labelText.setAttribute("id", base.id + "_HeaderText");
+        labelText.setAttribute("class", "GuiEditor_ImportEditorHeaderLabel");
+        header.appendChild(labelText);
+        base.addButtonToHeader(header, "_Button_Minimize", "GuiEditor_EditorButtonRight", " ");
+    };
+
+    base.createTree = function(p_callback) {
+        var data = base.viewmodel.getTreeData();
+        base.tree.jstree("destroy");
+        base.tree.jstree({
+            "core": {
+                "data": data,
+                "check_callback": function(operation, node, node_parent, node_position, more) {
+                    if (operation === "copy_node" && base.jsTreeUtils.isNodeFromTree(node, v_requestTree) && !base.jsTreeUtils.isRoot(node_parent) && base.jsTreeUtils.getIndexOfNode(node_parent, base.tree) === 1) {
+                        return true;
+                    } else if (operation === "copy_node") {
+                        return false;
+                    } else {
+                        return true;
+                    }
+                },
+                "multiple": false,
+                "animation": false,
+                "worker": false
+            },
+            "plugins" : ["contextmenu", "dnd"],
+            "dnd": {
+                "always_copy": true
+            },
+            "contextmenu": {
+                "items": function($node) {
+                    return {
+                        "Delete": {
+                            "label": "Delete",
+                            "action": function(data) {
+                                deleteNode(data.reference);
+                            }
+                        },
+                        "AddParam": {
+                            "label": "Add Parameter",
+                            "action": function(data) {
+                                paramAdded(data.reference);
+                            }
+                        },
+                        "RenameParam": {
+                            "label": "Rename Parameter",
+                            "action": function(data) {
+                                paramRenamed(data.reference);
+                            }
+                        }
+                    };
+                },
+                "select_node": false
+            }
+        });
+
+        base.tree.bind("copy_node.jstree", function(e, data) {
+            requestAdded(data, true);
+        });
+
+        base.tree.bind("select_node.jstree", function(e, data) {
+            if (v_selectedNode == data.node.id) {
+                data.instance.deselect_node(data.node);
+                v_selectedNode = undefined;
+            } else {
+                v_selectedNode = data.node.id;
+            }
+        });
+
+        base.tree.bind("redraw.jstree", function(e, data) {
+            document.getElementById(base.id).style.height = "auto";
+            document.getElementById(base.id).style.width = "auto";
+        });
+
+        base.tree.bind("ready.jstree", function(e, data) {
+            p_callback(true);
+        });
+
+        base.openNodes();
+
+        base.tree.bind("after_open.jstree after_close.jstree", function(e, data) {
+            document.getElementById(base.id).style.height = "auto";
+            document.getElementById(base.id).style.width = "auto";
+            base.saveOpenNodes();
+        });
+    };
+
+    ///////////////////// HANDLING EVENTS //////////////////////////////
+
+    base.setupCallbacks = function() {
+        $("#" + base.id + "_Header").on('contextmenu', function(event) {
+            var list = [
+                {
+                    "text": "change setup",
+                    "callback": changeSetup
+                },
+                {
+                    "text": "show only this",
+                    "callback": base.showOnlyThis
+                },
+                {
+                    "text": "show all",
+                    "callback": base.showAll
+                },
+                {
+                    "text": "delete",
+                    "callback": base.remove
+                }
+            ];
+
+            base.parent.openContextMenu(list, $("#" + base.id).offset());
+
+            event.preventDefault();
+            return false;
+        });
+
+        base.setupMinimizedCallback();
+    };
+
+    base.editorDeleted = function() {
+        base.parent.editorDeleted("Import", v_this);
+    };
+
+    ///////////////////// HANDLING OWN EVENTS //////////////////////////////
+
+    function changeSetup() {
+        function callback(setupName) {
+            base.viewmodel.setupNameChanged(setupName);
+            base.setHeaderText();
+        }
+        base.parent.getSetups(callback);
+    }
+
+    function requestAdded(data, deleteNeeded) {
+        if (deleteNeeded) {
+            base.tree.jstree("delete_node", data.node.id);
+        }
+
+        var requestPath = base.jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.original.id)).path;
+        base.viewmodel.setRequestPath(requestPath);
+        if (v_requestConnectionPresent) {
+            base.refreshConnections();
+        } else {
+            v_requestConnectionPresent = true;
+            base.parent.addEndpoint(requestConnectionEndpoint);
+            base.refreshConnections();
+        }
+    }
+
+    function deleteNode(data) {
+        var treeNode = base.tree.jstree("get_node", data);
+        var path = base.jsTreeUtils.getPath(base.tree.jstree("get_node", treeNode.id)).path;
+        if (path[0] == 1 && v_requestConnectionPresent) {
+            v_requestConnectionPresent = false;
+            base.viewmodel.setRequestPath(undefined);
+            base.parent.deleteEndpoint(requestConnectionEndpoint);
+        } else if (path[0] == 2 && path.length == 2) {
+            base.viewmodel.removeSetupParam(treeNode.text.split(": ")[0]);
+            base.tree.jstree("delete_node", treeNode);
+        }
+        base.saveOpenNodes();
+    }
+
+    function paramAdded(data) {
+        var name = prompt("Param name: ");
+        if (name != undefined) {
+            var value = prompt("Param value: ");
+            if (value != undefined) {
+                base.viewmodel.addSetupParam(name, value);
+                var id = base.jsTreeUtils.getNodeIdFromPath(base.tree, [2]);
+                base.tree.jstree("create_node", id, name + ": " + value);
+            }
+        }
+    }
+
+    function paramRenamed(data) {
+        var treeNode = base.tree.jstree("get_node", data);
+        var path = base.jsTreeUtils.getPath(base.tree.jstree("get_node", treeNode.id)).path;
+        if (path.length == 2) {
+            var old_name = treeNode.text.split(": ")[0];
+            var value = treeNode.text.split(": ")[1];
+            var name = prompt("New param name: ", old_name);
+            if (name != undefined) {
+                value = prompt("New param value: ", value);
+                if (value != undefined) {
+                    base.viewmodel.removeSetupParam(old_name);
+                    base.viewmodel.addSetupParam(name, value);
+                    base.tree.jstree("rename_node", treeNode, name + ": " + value);
+                }
+            }
+        }
+    }
+
+    ///////////////////// HANDLING CONNECTIONS //////////////////////////////
+
+    var viewConnectionPoint = {
+        "getOffset": function() {
+            var htmlObj;
+
+            if (!base.isVisible) {
+                var id = base.id + "_Header";
+                htmlObj = $("#" + id);
+            } else {
+                var id = base.jsTreeUtils.getLastNodeIdFromPath(base.tree, [0]);
+                htmlObj = $("#" + id + "_anchor");
+            }
+
+            var offset = htmlObj.offset();
+            offset.left += htmlObj.width();
+            offset.top += htmlObj.height() / 2;
+            return offset;
+        },
+
+        "getZIndex": function() {
+            return base.zIndex + 1;
+        },
+
+        "isEnabled": function() {
+            return base.isEnabled;
+        },
+
+        "object": v_this
+    };
+
+    var requestConnectionEndpoint = {
+        "getOffset": function() {
+            var htmlObj;
+
+            if (!base.isVisible) {
+                var id = base.id + "_Header";
+                htmlObj = $("#" + id);
+            } else {
+                var id = base.jsTreeUtils.getLastNodeIdFromPath(base.tree, [1]);
+                htmlObj = $("#" + id + "_anchor");
+            }
+
+            var offset = htmlObj.offset();
+            offset.top += htmlObj.height() / 2;
+            return offset;
+        },
+
+        "getZIndex": function() {
+            return base.zIndex + 1;
+        },
+
+        "isEnabled": function() {
+            return base.isEnabled;
+        },
+
+        "endpointType": "source",
+        "connectionType": "R_I",
+        "object": v_this,
+        "options": {
+            "stroke": "#cc9c5c"
+        },
+        "identifier": function() {
+            return base.viewmodel.getRequestPath();
+        }
+    };
+
+    this.getEndpoint = function(identifier) {
+        if (identifier == base.viewmodel.getParentId()) {
+            return viewConnectionPoint;
+        } else {
+            return undefined;
+        }
+    };
+
+    this.getConnectionInformation = function(identifier) {
+        var parentId = base.viewmodel.getParentId();
+        if (identifier.type == "set" && base.tree.jstree("get_node", identifier.treeId)) {
+            base.viewmodel.setParentId(identifier.parentId);
+            return parentId;
+        } else if (identifier.type == "get" && identifier.parentId == base.viewmodel.getParentId()) {
+            return parentId;
+        } else {
+            return undefined;
+        }
+    };
+
+    this.getEndpoints = function() {
+        if (v_requestConnectionPresent) {
+            return [requestConnectionEndpoint];
+        } else {
+            return [];
+        }
+    };
+}
+//# sourceURL=GuiEditor\Views\View_Imports.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/Views/View_JSONConfigEditor.js b/htdocs/WebApplications/GuiEditor/Views/View_JSONConfigEditor.js
new file mode 100644
index 0000000..2c6fbb1
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_JSONConfigEditor.js
@@ -0,0 +1,78 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_JSONConfigEditor_View(p_viewmodel, p_id) {
+    "use strict";
+
+    var v_viewmodel = p_viewmodel;
+    var v_id = p_id;
+
+    var v_this = this;
+
+    this.applicationCreated = function() {
+        $('#' + v_id + '_Button_Save').on("click", save);
+        $('#' + v_id + '_Button_Load').on("click", load);
+        $('#' + v_id + '_Button_Save').prop("disabled", true);
+    };
+
+    function load() {
+        v_this.close();
+        v_this.refresh();
+    }
+
+    function save() {
+        v_viewmodel.save();
+    }
+
+    function startJSONEditor() {
+        var editor = new CView_JSONEditor([v_viewmodel], v_id + '_Editor', v_id + "_EditorContainer", {"headerText": v_viewmodel.getName()});
+        editor.applicationCreated();
+        editor.refresh(true);
+    }
+
+    function startCodeEditor() {
+        var editor = new CView_CodeEditor([v_viewmodel], v_id + '_Editor', v_id + "_EditorContainer", {"editorType": "json", "formatAllowed": true, "headerText": v_viewmodel.getName()});
+        editor.applicationCreated();
+        editor.refresh(true);
+    }
+
+    this.refresh = function() {
+        function configLoaded(ok) {
+            if (ok) {
+                if (v_viewmodel.isSchemaPresent()) {
+                    startJSONEditor();
+                } else {
+                    startCodeEditor();
+                }
+                $('#' + v_id + '_Button_Save').prop("disabled", false);
+            } else {
+                alert("Loading config failed.");
+            }
+        }
+
+        function gotConfig(p_config) {
+            v_viewmodel.loadConfig(p_config, configLoaded);
+        }
+
+        function optionsArrived(options) {
+            var dialog = new ChoiceDialog(v_id, "GuiEditor_Dialog_ChooseConfig", {
+                "header": "Select config",
+                "text": "Please select a config to edit from the table below.",
+                "choices": options,
+                "callback": gotConfig
+            });
+            dialog.open();
+        }
+
+        $('#' + v_id + '_Button_Save').prop("disabled", true);
+        v_viewmodel.listEditableConfigs(optionsArrived);
+    };
+
+    this.close = function() {
+        $('#' + v_id + '_EditorContainer').empty();
+        $('#' + v_id + '_Button_Save').prop("disabled", true);
+    };
+}
+//# sourceURL=GuiEditor\Views\View_JSONConfigEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/Views/View_RequestEditor.js b/htdocs/WebApplications/GuiEditor/Views/View_RequestEditor.js
new file mode 100644
index 0000000..e873d0e
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_RequestEditor.js
@@ -0,0 +1,588 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_RequestEditor_View(p_viewModel, p_parent) {

+    "use strict";

+

+    var v_viewModel = p_viewModel.getRequestEditorViewModel();

+    var v_parent = p_parent;

+

+    var v_desktopData;

+    var v_helpTree;

+    var v_requestTree;

+    var v_elementEditor;

+    var v_filterEditor;

+    var v_editorContainer = new GuiEditor_EditorContainer_View(p_viewModel, "GuiEditor_Playground", this);

+    var v_checkDisabled = false;

+    var v_this = this;

+

+    var jsTreeUtils = new JsTreeUtils();

+

+    ///////////////////// GETTER FOR SUBVIEWS //////////////////////////////

+

+    this.getEditorContainerView = function() {

+        return v_editorContainer;

+    };

+

+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////

+

+    this.applicationCreated = function() {

+        var aligner = new CView_Aligner([], "GuiEditor_RequestEditorSplit", undefined, {

+            "existing": true,

+            "resizable": true

+        });

+        aligner.applicationCreated();

+

+        v_desktopData = v_viewModel.getDesktopData();

+        v_helpTree = $("#GuiEditor_HelpTree");

+        v_requestTree = $("#GuiEditor_RequestTree");

+        v_editorContainer.applicationCreated();

+

+        v_elementEditor = new GuiEditor_ElementEditor_View(p_viewModel, "GuiEditor_Playground", "GuiEditor_ElementEditor", v_this);

+        v_filterEditor = new GuiEditor_FilterEditor_View(p_viewModel, "GuiEditor_Playground", "GuiEditor_FilterEditor", v_this, v_requestTree, v_helpTree);

+

+        setupCallbacks();

+    };

+

+    this.setFocusedObj = function(p_object) {

+        v_parent.setFocusedObj(p_object);

+    };

+

+    this.setDefaultZidx = function() {};

+    this.setZidx = function() {};

+    this.deletePressed = function() {

+        var selected = v_requestTree.jstree("get_selected")[0];

+        if (selected != undefined) {

+            deleteNode(selected);

+        }

+    };

+

+    this.fullRefresh = function() {

+        v_desktopData = v_viewModel.getDesktopData();

+        function viewsInitialized() {

+            v_editorContainer.fullRebuildConnections();

+            v_editorContainer.refreshConnections();

+            v_parent.toggleButtons(true);

+

+            $(document).on("keydown", toggleValidation);

+            $(document).on("keyup", toggleValidation);

+        }

+

+        var taskList = new TaskList([new GenericTask(createViewElements), new GenericTask(v_editorContainer.createViewsFromExistingData)], viewsInitialized);

+        taskList.taskOperation();

+    };

+

+    this.destroy = function() {

+        closeEditors();

+        $(document).off('dnd_move.vakata', helpToRequestDrag);

+        $(document).off('dnd_stop.vakata', helpToRequestDrop);

+        $(document).off('dnd_stop.vakata', requestToHelpDrop);

+        $(document).off("keydown", toggleValidation);

+        $(document).off("keyup", toggleValidation);

+        v_editorContainer.destroy();

+        v_requestTree.jstree("destroy");

+    };

+

+    this.search = function(string) {

+        var nodes = $("#GuiEditor_RequestTree li");

+        for (var i = 0; i < nodes.length; ++i) {

+            var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", $(nodes[i]))).path;

+            if (v_viewModel.matches(string, path)) {

+                $(nodes[i]).addClass("found");

+            }

+        }

+    };

+

+    ///////////////////// INTERACTION WITH OUTHER VIEWS //////////////////////////////

+

+    this.getRequestTree = function() {

+        return v_requestTree;

+    };

+

+    this.requestRenamed = function(p_path, name) {

+        v_requestTree.jstree("rename_node", jsTreeUtils.getLastNodeIdFromPath(v_requestTree, p_path), name);

+        v_editorContainer.requestRenamed(p_path, name);

+    };

+

+    this.selectionAdded = function(path) {

+        v_viewModel.selectionAdded(path);

+    };

+

+    this.selectionOrFilterChanged = function(p_path, p_selection, p_filter, p_rangeFilter, p_writableInfo) {

+        var id = jsTreeUtils.getNodeIdFromPath(v_requestTree, mcopy(p_path));

+        if (id !== false) {

+            $("#" + id).removeClass("GuiEditor_NodeWithData GuiEditor_NodeWithSelection GuiEditor_NodeWithFilter GuiEditor_NodeWithRangeFilter GuiEditor_NodeWithWritableInfo");

+            var hasData = false

+            if (p_selection) {

+                $("#" + id).addClass("GuiEditor_NodeWithSelection");

+                hasData = true;

+            }

+            if (p_filter) {

+                $("#" + id).addClass("GuiEditor_NodeWithFilter");

+                hasData = true;

+            }

+            if (p_rangeFilter) {

+                $("#" + id).addClass("GuiEditor_NodeWithRangeFilter");

+                hasData = true;

+            }

+            if (p_writableInfo) {

+                $("#" + id).addClass("GuiEditor_NodeWithWritableInfo");

+                hasData = true;

+            }

+            if (hasData) {

+                $("#" + id).addClass("GuiEditor_NodeWithData");

+            }

+        }

+    };

+

+    ///////////////////// CREATING VIEW ELEMENTS AND INTERACTIONS //////////////////////////////

+

+    function createViewElements(callback) {

+        v_viewModel.getHelp(createHelpJSTree, v_desktopData["sortHelp"]);

+        v_viewModel.getRequestTree(function(data) {

+            createRequestJSTree(data, callback);

+        });

+    }

+

+    function createHelpJSTree(p_data) {

+        v_helpTree.jstree("destroy");

+        v_helpTree = v_helpTree.jstree({

+            "core": {

+                "data": p_data,

+                "check_callback" : function(operation, node, node_parent, node_position, more) {

+                     if (operation === "copy_node" || operation === "move_node") {

+                         return false;

+                     } else {

+                         return true;

+                     }

+                },

+                "multiple" : false,

+                "animation": false,

+                "worker": false

+            },

+            "plugins" : ["search", "dnd"],

+            "search" : {

+                "show_only_matches": true

+            },

+            "dnd": {

+                "always_copy": true

+            }

+        });

+

+        $(document).off('dnd_stop.vakata', requestToHelpDrop);

+        $(document).on('dnd_stop.vakata', requestToHelpDrop);

+

+        v_helpTree.bind("hover_node.jstree", function(e, data) {

+            $("#"+data.node.id).prop("title", data.node.data);

+        });

+    }

+

+    function createRequestJSTree(p_data, p_callback) {

+        v_requestTree.jstree("destroy");

+        v_requestTree = v_requestTree.jstree({

+            "core": {

+                "data": p_data,

+                "check_callback": function(operation, node, node_parent, node_position, more) {

+                    if (operation === "copy_node" && v_checkDisabled && jsTreeUtils.isNodeFromTree(node, v_helpTree) && jsTreeUtils.getDepth(node, v_helpTree) > 1 && $("#GuiEditor_RequestTree > ul").children().length > 0) {

+                        return true;

+                    } else if (operation === "copy_node" && jsTreeUtils.isNodeFromTree(node, v_helpTree) && $("#GuiEditor_RequestTree > ul").children().length > 0) {

+                        return dragFromHelpValidate(node.id, node_parent.id);

+                    } else if (operation === "copy_node" && jsTreeUtils.isNodeFromTree(node, v_requestTree)) {

+                        return dragFromRequestValidate(node.id, node_parent.id);

+                    } else if (operation === "copy_node" && node.text === "Selection connections" && node_parent.id != "#") {

+                        return true;

+                    } else if (operation === "copy_node" && node.text === "Request connection" && node_parent.id != "#") {

+                        return true;

+                    } else if (operation === "copy_node") {

+                        return false;

+                    } else {

+                        return true;

+                    }

+                },

+                "multiple": false,

+                "animation": false,

+                "worker": false

+            },

+            "plugins": ["contextmenu", "dnd"],

+            "dnd": {

+                "always_copy": true

+            },

+            "contextmenu": {

+                "items": function($node) {

+                    return {

+                        "Edit": {

+                            "label": "Edit request",

+                            "action": function(data) {

+                                var offset = data.reference.offset();

+                                offset.left += data.reference.width();

+

+                                v_elementEditor.open(jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.reference)).path, offset);

+                                v_parent.setFocusedObj(v_elementEditor);

+                            }

+                        },

+                        "EditFilter": {

+                            "label": "Edit filter",

+                            "action": function(data) {

+                                var offset = data.reference.offset();

+                                offset.left += data.reference.width();

+

+                                var node = v_requestTree.jstree("get_node", data.reference);

+                                v_filterEditor.open(jsTreeUtils.getPath(node).path, offset);

+                                v_parent.setFocusedObj(v_filterEditor);

+                            },

+                            "separator_after": true

+                        },

+                        "Add": {

+                            "label": "Add child request",

+                            "action": function(data) {

+                                var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.reference)).path;

+                                v_viewModel.addEmptyChildRequest(mcopy(path), 0, partialRefresh);

+                                path.push(0);

+                                var added = jsTreeUtils.getLastNodeIdFromPath(v_requestTree, path);

+                                v_requestTree.jstree("deselect_node", data.reference)

+                                v_requestTree.jstree("select_node", added);

+

+                                var offset = $("#" + added + "_anchor").offset();

+                                offset.left += $("#" + added + "_anchor").width();

+

+                                v_elementEditor.open(path, offset);

+                                v_parent.setFocusedObj(v_elementEditor);

+                            }

+                        },

+                        "Copy": {

+                            "label": "Copy",

+                            "action": function(data) {

+                                var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.reference)).path;

+                                v_viewModel.copyRequest(mcopy(path), partialRefresh);

+                                path[path.length - 1] += 1;

+                                var added = jsTreeUtils.getLastNodeIdFromPath(v_requestTree, path);

+                                v_requestTree.jstree("deselect_node", data.reference)

+                                v_requestTree.jstree("select_node", added);

+                            }

+                        },

+                        "Delete": {

+                            "label": "Delete",

+                            "action": function(data) {

+                                deleteNode(data.reference);

+                            },

+                            "separator_after": true

+                        },

+                        "SizeOf": {

+                            "label": "Convert to sizeOf",

+                            "action": function(data) {

+                                var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.reference)).path;

+                                v_viewModel.convertToSizeOf(path, v_this.requestRenamed);

+                            }

+                        },

+                        "ElementPresent": {

+                            "label": "Convert to dataElementPresent",

+                            "action": function(data) {

+                                var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.reference)).path;

+                                v_viewModel.convertToDataElementPresent(path, v_this.requestRenamed);

+                            },

+                            "separator_after": true

+                        },

+                        "ExpandAll": {

+                            "label": "Expand all",

+                            "action": function(data) {

+                                v_requestTree.jstree("open_all");

+                            }

+                        },

+                        "CollapseAll": {

+                            "label": "Collapse all",

+                            "action": function(data) {

+                                v_requestTree.jstree("close_all");

+                            },

+                            "separator_after": true

+                        },

+                        "CopyRequestAsText": {

+                            "label": "Copy Request as Text",

+                            "action": function(data) {

+                                var text = JSON.stringify(v_viewModel.getRequest(), null, 4);

+

+                                var textArea = document.createElement("textarea");

+                                textArea.style.position = 'fixed';

+                                textArea.style.top = 0;

+                                textArea.style.left = 0;

+                                textArea.style.width = '2em';

+                                textArea.style.height = '2em';

+                                textArea.style.padding = 0;

+                                textArea.style.border = 'none';

+                                textArea.style.outline = 'none';

+                                textArea.style.boxShadow = 'none';

+                                textArea.style.background = 'transparent';

+                                textArea.value = text;

+

+                                document.body.appendChild(textArea);

+                                textArea.select();

+                                document.execCommand('copy');

+                                document.body.removeChild(textArea);

+                            }

+                        }

+                    };

+                },

+                "select_node": true

+            }

+        });

+

+        v_requestTree.bind("hover_node.jstree", function(e, data) {

+            var string = JSON.stringify(v_viewModel.getRequestCopy(jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.node.id)).path), null, 4);

+            $("#"+data.node.id).prop("title", string);

+        });

+

+        v_requestTree.bind("select_node.jstree", function (e, data) {

+            closeEditors();

+            v_parent.setFocusedObj(v_this);

+        });

+

+        v_requestTree.bind("copy_node.jstree", function(e, data) {

+            if (jsTreeUtils.isNodeFromTree(data.original, v_helpTree)) {

+                helpNodeCopied(data);

+            } else if (jsTreeUtils.isNodeFromTree(data.original, v_requestTree)) {

+                requestNodeCopied(data);

+            } else if (data.original.text === "Selection connections") {

+                v_requestTree.jstree("delete_node", data.node.id);

+                v_editorContainer.selectionAddedInRequestTree(data.parent, data.original.id);

+            } else if (data.original.text === "Request connection") {

+                v_requestTree.jstree("delete_node", data.node.id);

+                v_editorContainer.importAddedInRequestTree(data.parent, data.original.id);

+            }

+        });

+

+        jsTreeUtils.openNodes(v_requestTree, v_desktopData.openRequests);

+

+        v_requestTree.bind("after_open.jstree after_close.jstree", function(e, data) {

+            v_editorContainer.refreshConnections(v_this);

+            v_desktopData.openRequests = jsTreeUtils.findOpenNodes(v_requestTree);

+        });

+

+        v_requestTree.bind("after_open.jstree delete_node.jstree ready.jstree", function(e, data) {

+            // some operations are async and even their callback gets called too soon... so we have to use a timeout

+            // after_open, when we open a node, or when we insert one, delete_node, when we delete a node, and ready when the tree gets drawn in the beginning

+            setTimeout(function() {

+                v_viewModel.findSelectionsAndFilters();

+            }, 100);

+        });

+

+        v_requestTree.bind("ready.jstree", function(e, data) {

+            p_callback(true);

+        });

+

+        $(document).off('dnd_move.vakata', helpToRequestDrag);

+        $(document).on('dnd_move.vakata', helpToRequestDrag);

+

+        $(document).off('dnd_stop.vakata', helpToRequestDrop);

+        $(document).on('dnd_stop.vakata', helpToRequestDrop);

+    }

+

+    function helpToRequestDrag(event, data) {

+        var node = {

+            "id": data.data.nodes[0]

+        }

+        if ($(data.event.target).attr("id") == "GuiEditor_RequestTree" && jsTreeUtils.isNodeFromTree(node, v_helpTree) && (v_checkDisabled || dragFromHelpValidate(data.data.nodes[0], "#"))) {

+            data.helper.find('.jstree-icon').removeClass('jstree-er').addClass('jstree-ok');

+        }

+    }

+

+    function helpToRequestDrop(event, data) {

+        var node = {

+            "id": data.data.nodes[0]

+        }

+        if ($(data.event.target).attr("id") == "GuiEditor_RequestTree" && jsTreeUtils.isNodeFromTree(node, v_helpTree) && (v_checkDisabled || dragFromHelpValidate(data.data.nodes[0], "#"))) {

+            var helpPath = jsTreeUtils.getPath(v_helpTree.jstree("get_node", node.id)).path;

+            var position = $("#GuiEditor_RequestTree > ul").children().length;

+            v_viewModel.createRequest(helpPath, position, partialRefresh);

+            v_viewModel.findSelectionsAndFilters();

+        }

+    }

+

+    function requestToHelpDrop(event, data) {

+        var node = {

+            "id": data.data.nodes[0]

+        }

+        if (($(data.event.target).attr("id") == "GuiEditor_HelpTree" || jsTreeUtils.isNodeFromTree({"id": $(data.event.target).attr("id")}, v_helpTree)) && jsTreeUtils.isNodeFromTree({"id": data.data.nodes[0]}, v_requestTree)) {

+            deleteNode(v_requestTree.jstree("get_node", node.id));

+        }

+    }

+

+    function setupCallbacks() {

+        $("#GuiEditor_HelpSearch").on("input", function() {

+            v_helpTree.jstree("search", $(this).val());

+        });

+        $("#GuiEditor_Button_AddRequest").on("click", addEmptyRequest);

+

+        $("#GuiEditor_SortHelpTree").button().click(function(event, ui) {

+            if($(this).prop('checked')) {

+                v_viewModel.getHelp(createHelpJSTree, true);

+                v_desktopData["sortHelp"] = true;

+            } else {

+                v_viewModel.getHelp(createHelpJSTree, false);

+                v_desktopData["sortHelp"] = false;

+            }

+        });

+

+        if (v_desktopData["sortHelp"]) {

+            $("#GuiEditor_SortHelpTree").prev().addClass('ui-state-active');

+            $("#GuiEditor_SortHelpTree").prop('checked', true);

+        }

+    }

+

+    function partialRefresh(p_path, p_data) {

+        var parentId = getParentNodeIdFromPath(p_path);

+        v_requestTree.jstree("create_node", parentId, p_data.text, p_path[p_path.length - 1]);

+        v_requestTree.jstree("open_node", parentId);

+

+        v_editorContainer.updatePaths(p_path, 1);

+        v_editorContainer.refreshConnections(v_this);

+    }

+

+    function closeEditors() {

+        v_elementEditor.close();

+        v_filterEditor.close();

+        v_viewModel.findSelectionsAndFilters();

+    }

+

+    ///////////////////// HANDLING EVENTS //////////////////////////////

+

+    function helpNodeCopied(data) {

+        closeEditors();

+        v_requestTree.jstree("delete_node", data.node.id);

+        var helpPath = jsTreeUtils.getPath(v_helpTree.jstree("get_node", data.original.id)).path;

+        if (data.parent === "#") {

+            v_viewModel.createRequest(helpPath, data.position, partialRefresh);

+        } else {

+            var requestPath = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.parent)).path;

+            v_viewModel.addChildRequest(helpPath, requestPath, data.position, partialRefresh);

+        }

+    }

+

+    function requestNodeCopied(data) {

+        closeEditors();

+        v_requestTree.jstree("delete_node", data.node.id);

+        var fromPathObj = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.original.id));

+        var fromPath = fromPathObj.path;

+        var fromPathStr = fromPathObj.strpath;

+        var toPath = [];

+        var toPathStr = "";

+        if (data.parent != "#") {

+            var toPathObj = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.parent));

+            toPath = toPathObj.path;

+            toPathStr = toPathObj.strpath;

+        }

+        v_viewModel.moveRequest(fromPath, toPath, data.position);

+

+        function moveComplete(node, parent, pos) {

+            toPath.push(data.position);

+            v_editorContainer.pathsMoved(fromPath, fromPathStr, toPath, toPathStr);

+            v_requestTree.jstree("open_node", parent);

+            v_editorContainer.refreshConnections(v_this);

+        }

+

+        v_requestTree.jstree("move_node", v_requestTree.jstree("get_node", data.original.id), v_requestTree.jstree("get_node", data.parent), data.position, moveComplete);

+    }

+

+    function dragFromHelpValidate(p_helpId, p_requestParentId) {

+        var helpPath = jsTreeUtils.getPath(v_helpTree.jstree("get_node", p_helpId)).path;

+        if (p_requestParentId === "#") {

+            return v_viewModel.isValidToCreateRequest(helpPath);

+        } else {

+            var requestPath = jsTreeUtils.getPath(v_requestTree.jstree("get_node", p_requestParentId)).path;

+            return v_viewModel.isValidToAddRequest(helpPath, requestPath);

+        }

+    }

+

+    function dragFromRequestValidate(p_fromId, p_toId) {

+        var fromPath = jsTreeUtils.getPath(v_requestTree.jstree("get_node", p_fromId)).path;

+        var toPath;

+        if (p_toId != "#") {

+            toPath = jsTreeUtils.getPath(v_requestTree.jstree("get_node", p_toId)).path;

+        } else {

+            toPath = [];

+        }

+

+        return v_viewModel.isValidToMoveRequest(fromPath, toPath);

+    }

+

+    function getParentNodeIdFromPath(p_path) {

+        if (p_path.length === 1) {

+            return "#";

+        } else {

+            var id = "#";

+            for (var i = 0; i < p_path.length - 1; ++i) {

+                id = v_requestTree.jstree("get_node", id).children[p_path[i]];

+            }

+            return id;

+        }

+    }

+

+    function addEmptyRequest() {

+        closeEditors();

+

+        v_viewModel.createEmptyRequest(0, partialRefresh);

+        v_requestTree.jstree("deselect_node", v_requestTree.jstree("get_selected"));

+        var newNodeId = jsTreeUtils.getLastNodeIdFromPath(v_requestTree, [0]);

+        v_requestTree.jstree("select_node", newNodeId);

+

+        var offset = $("#" + newNodeId + "_anchor").offset();

+        offset.left += $("#" + newNodeId + "_anchor").width();

+

+        v_elementEditor.open([0], offset);

+        v_parent.setFocusedObj(v_elementEditor);

+    }

+

+    function deleteNode(p_data) {

+        var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", p_data)).path;

+        v_viewModel.deleteRequest(mcopy(path));

+

+        v_requestTree.jstree("delete_node", p_data);

+        closeEditors();

+

+        v_editorContainer.updatePaths(mcopy(path), -1);

+        v_editorContainer.refreshConnections(v_this);

+

+        v_desktopData.openRequests = jsTreeUtils.findOpenNodes(v_requestTree);

+    }

+

+    function toggleValidation(event) {

+        if (event.keyCode == 17) {

+            if (event.type == "keydown") {

+                v_checkDisabled = true;

+            } else {

+                v_checkDisabled = false;

+            }

+        }

+    }

+

+    ///////////////////// CONNECTION RELATED /////////////////////

+

+    function RequestEndpoint(p_identifier) {

+        var v_identifier = p_identifier;

+

+        this.getOffset = function() {

+

+            var id = jsTreeUtils.getLastNodeIdFromPath(v_requestTree, v_identifier());

+            var htmlObj = $("#" + id + "_anchor");

+

+            var offset = htmlObj.offset();

+            offset.top += htmlObj.height() / 2;

+            offset.left += htmlObj.width()

+            return offset;

+        };

+

+        this.object = v_this;

+    }

+

+    this.getEndpoint = function(identifier) {

+        return new RequestEndpoint(identifier);

+    };

+

+    this.getConnectionInformation = function(identifier) {

+        return jsTreeUtils.getPath(v_requestTree.jstree("get_node", identifier));

+    };

+

+    this.disabled = function() {};

+}

+

+//# sourceURL=GuiEditor\Views\View_RequestEditor.js

diff --git a/htdocs/WebApplications/GuiEditor/Views/View_ViewContentEditor.js b/htdocs/WebApplications/GuiEditor/Views/View_ViewContentEditor.js
new file mode 100644
index 0000000..070f394
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_ViewContentEditor.js
@@ -0,0 +1,189 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_ViewContentEditor_View(p_viewmodel, p_id) {
+
+    var base = new GuiEditor_BaseContentEditor_View(p_viewmodel, p_id);
+
+    var HTML_OF_TAB = '' +
+        '<li>' +
+            '<a href="#{0}">{1}</a>' +
+            '<span class="ui-icon ui-icon-close">Remove Tab</span>' +
+        '</li>';
+
+    var HTML_OF_FILETABS = '' +
+        '<div id="{0}">' +
+            '<div id="{0}_Tabs">' +
+                '<ul>' +
+                    '<li><a {1}href="#{0}_Html">HTML</a></li>' +
+                    '<li><a {1}href="#{0}_Css">CSS</a></li>' +
+                    '<li><a {1}href="#{0}_Js">JavaScript</a></li>' +
+                '</ul>' +
+                '<div id="{0}_Html"></div>' +
+                '<div id="{0}_Css"></div>' +
+                '<div id="{0}_Js"></div>' +
+            '</div>' +
+        '</div>';
+
+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////
+
+    this.applicationCreated = function() {
+        base.applicationCreated();
+        setupCallbacks();
+    };
+
+    function setupCallbacks() {
+        $("#" + base.viewId + "_Button_New").on("click", newTab);
+        $("#" + base.viewId + "_Button_Load").on("click", load);
+        $("#" + base.viewId + "_Button_LoadTemplate").on("click", loadTemplate);
+        $("#" + base.viewId + "_Button_Save").on("click", save);
+        $("#" + base.viewId + "_Button_SaveAs").on("click", saveAs);
+    }
+
+    ///////////////////// HANDLING TABS AND PANELS //////////////////////////////
+
+    function getCurrentlyOpenFilePanel(activePanel) {
+        if (activePanel == undefined) {
+            activePanel = base.getCurrentlyOpenPanel();
+        }
+        return $("#" + activePanel.attr("id") + " div.ui-tabs-panel[aria-hidden='false']");
+    }
+
+    base.getPanelOnActivation = function(panel) {
+        return getCurrentlyOpenFilePanel(panel);
+    };
+
+    this.applicationFocused = base.applicationFocused;
+
+    base.getPanelOnFocus = function() {
+        return getCurrentlyOpenFilePanel();
+    };
+
+    base.getEditedTab = function() {
+        return base.getCurrentlyOpenPanel().find(".ui-tabs-active a");
+    };
+
+    base.getIdOfPanelContainingEditor = function() {
+        return getCurrentlyOpenFilePanel().attr("id");
+    };
+
+    ///////////////////// HANDLING EVENTS //////////////////////////////
+
+    function save() {
+        base.save(saveAs);
+    }
+
+    function saveAs() {
+        function viewSaved(name, ok, id, existingId) {
+            if (!ok) {
+                alert("Failed to save view " + name);
+            } else {
+                base.changeTabName(name);
+                base.setEdited(false, id + "_Html");
+                base.setEdited(false, id + "_Css");
+                base.setEdited(false, id + "_Js");
+                if (existingId != undefined) {
+                    $("a[href$=" + existingId + "]").next("span").click();
+                }
+            }
+        }
+
+        base.saveAs(base.viewmodel.viewExists, base.viewmodel.saveViewAs, "View", viewSaved);
+    }
+
+    function createTab(id, name, operation) {
+        if (operation == "exists") {
+            base.fileTabs.tabs("option", "active", $('a[href$=' + id + ']').parent().index());
+            return;
+        }
+
+        base.fileTabs.find(".ui-tabs-nav").first().append(HTML_OF_TAB.format(id, name));
+        if (operation == "new") {
+            base.fileTabs.append(HTML_OF_FILETABS.format(id, 'class="file-changed" '));
+        } else {
+            base.fileTabs.append(HTML_OF_FILETABS.format(id, ""));
+        }
+
+        base.fileTabs.tabs("refresh");
+
+        var tabs = $("#" + id + "_Tabs").tabs({
+            "active": 0,
+            activate: function(ev, ui) {
+                base.panelActivated(ui.newPanel);
+            }
+        });
+
+        base.fileTabs.tabs("option", "active", $("#" + base.viewId + "_Tabs > ul > li").last().index());
+    }
+
+    function newTab() {
+        base.viewmodel.newViewContent(createTab);
+    }
+
+    function load() {
+        function gotViewName(viewName) {
+            base.viewmodel.loadViewContent(viewName, createTab);
+        }
+
+        function optionsArrived(options) {
+            var dialog = new ChoiceDialogWithButton(base.viewId, "GuiEditor_Dialog_LoadView", {
+                "header": "Select a view",
+                "text": "Please select a view from the table below.",
+                "choices": options,
+                "callback": gotViewName,
+                "buttonHandler": deleteView,
+                "buttonText": "X",
+                "buttonStyle": "color: red;",
+                "closeOnButtonPress": true
+            });
+            dialog.open();
+        }
+
+        base.viewmodel.listViews(optionsArrived);
+    }
+
+    function loadTemplate() {
+        function gotViewName(viewName) {
+            base.viewmodel.loadViewTemplate(viewName, createTab);
+        }
+
+        function optionsArrived(options) {
+            var dialog = new ChoiceDialog(base.viewId, "GuiEditor_Dialog_LoadView", {
+                "header": "Select a view",
+                "text": "Please select a view from the table below.",
+                "choices": options,
+                "callback": gotViewName
+            });
+            dialog.open();
+        }
+
+        base.viewmodel.listViewTemplates(optionsArrived);
+    }
+
+    function deleteView(viewName) {
+        var text = "Are you sure your want to delete view " + viewName + "?";
+
+        function viewDeleted(ok, id) {
+            if (!ok) {
+                alert("Failed to delete view " + viewName);
+            } else if (id != undefined) {
+                base.setEdited(true, id + "_Html");
+                base.setEdited(true, id + "_Css");
+                base.setEdited(true, id + "_Js");
+            }
+            load();
+        }
+
+        var dialog = new ConfirmationDialog(base.viewId, "GuiEditor_Dialog_DeleteView", {
+            "header": "Delete view",
+            "text": text,
+            "callback": function() {
+                base.viewmodel.deleteView(viewName, viewDeleted);
+            }
+        });
+        dialog.open();
+    }
+}
+//# sourceURL=GuiEditor\Views\View_ViewContentEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/Views/View_ViewEditor.js b/htdocs/WebApplications/GuiEditor/Views/View_ViewEditor.js
new file mode 100644
index 0000000..87b57bf
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_ViewEditor.js
@@ -0,0 +1,466 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_ViewEditor_View(p_viewModel, p_parentId, p_viewId, p_parent, p_desktopData) {

+    "use strict";

+

+    var base = new GuiEditor_BaseEditor_View(p_viewModel, p_parentId, p_viewId, p_parent, p_desktopData, this);

+

+    var v_this = this;

+    var v_selectedNode = "";

+

+    var viewmodelConnections = [];

+    var viewConnections = [];

+

+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////

+

+    this.init = function(callback) {

+        base.init(callback, "GuiEditor_ViewEditor", 610);

+

+        var viewmodelIndexes = base.viewmodel.getViewModelIndexes();

+        for (var i = 0; i < viewmodelIndexes.length; ++i) {

+            var endpoint = new ViewmodelConnectionEndpoint([0, i], viewmodelIndexes[i]);

+            viewmodelConnections.push(endpoint);

+        }

+

+        var childIds = base.viewmodel.getChildIds();

+        for (var i = 0; i < childIds.length; ++i) {

+            var endpoint = getViewEndpoint([2, i], childIds[i]);

+            viewConnections.push(endpoint);

+        }

+

+        base.validate();

+    };

+

+    this.destroy = base.destroy;

+    this.setDefaultZidx = base.setDefaultZidx;

+    this.setZidx = base.setZidx;

+    this.deletePressed = function() {

+        var node = base.tree.jstree("get_selected");

+        if (node.length > 0) {

+            deleteNode(node);

+        }

+    };

+

+    ///////////////////// GENERAL EDITOR VIEW FUNCTIONS //////////////////////////////

+

+    this.disabled = base.disabled;

+    this.isNodeFromTree = base.isNodeFromTree;

+    this.search = base.search;

+    this.validate = base.validate;

+

+    ///////////////////// VIEW EDITOR SPECIFIC FUNCTIONS //////////////////////////////

+

+    this.wouldCreateACycle = function(node, id) {

+        if (base.jsTreeUtils.isNodeFromTree(node, base.tree)) {

+            return base.viewmodel.wouldCreateACycle(id);

+        } else {

+            return false;

+        }

+    };

+

+    this.removeViewConnection = function(connectionIndex) {

+        base.connectionDeleted(viewConnections, connectionIndex);

+        base.createTree(function() {

+            base.tree.jstree("open_all");

+            base.refreshConnections();

+        });

+        base.validate();

+    };

+

+    this.removeViewmodelConnection = function(viewmodelIndex) {

+        var indexes = base.viewmodel.getViewModelIndexes();

+        var index = indexes.indexOf(viewmodelIndex);

+

+        base.viewmodel.viewModelDeleted(viewmodelIndex);

+

+        if (index != -1) {

+            base.connectionDeleted(viewmodelConnections, index);

+            base.createTree(function() {

+                base.tree.jstree("open_all");

+                base.refreshConnections();

+            });

+            base.validate();

+        }

+    };

+

+    ///////////////////// CREATING THE VIEW //////////////////////////////

+

+    base.fillHeader = function(header) {

+        base.addButtonToHeader(header, "_Button_Edit", "GuiEditor_EditorButtonLeft", "EDIT");

+        var labelText = document.createElement("label");

+        labelText.setAttribute("id", base.id + "_HeaderText");

+        labelText.setAttribute("class", "GuiEditor_ViewEditorHeaderLabel");

+        header.appendChild(labelText);

+        base.addButtonToHeader(header, "_Button_Minimize", "GuiEditor_EditorButtonRight", " ");

+    };

+

+    base.createTree = function(p_callback) {

+        var data = base.viewmodel.getTreeData();

+        base.tree.jstree("destroy");

+        base.tree.jstree({

+            "core": {

+                "data": data,

+                "check_callback": function(operation, node, node_parent, node_position, more) {

+                    if (operation === "copy_node") {

+                        if (base.jsTreeUtils.isRoot(node_parent)) {

+                            return false;

+                        }

+                        return isViewModelConnection(node, node_parent) || isAllowedViewConnection(node, node_parent, node_position) || isImportConnection(node, node_parent) || (base.jsTreeUtils.isNodeFromTree(node, base.tree) && base.jsTreeUtils.isTheParentOfNode(node, node_parent, base.tree));

+                    } else {

+                        return true;

+                    }

+                },

+                "multiple": false,

+                "animation": false,

+                "worker": false

+            },

+            "plugins": ["contextmenu", "dnd"],

+            "contextmenu": {

+                "items": function($node) {

+                    return {

+                        "Delete": {

+                            "label": "Delete",

+                            "action": function(data) {

+                                deleteNode(data.reference);

+                            }

+                        }

+                    };

+                },

+                "select_node": false

+            },

+            "dnd": {

+                "always_copy": true

+            }

+        });

+

+        base.tree.bind("copy_node.jstree", function(e, data) {

+

+            if (base.tree.jstree("get_node", data.original.id)) {

+                connectionMoved(data);

+            } else if (data.original.text == "View connection point") {

+                viewModelAdded(data);

+            } else if (data.original.text == "Child of ...") {

+                viewAdded(data);

+            } else if (data.original.text == "Import into ...") {

+                viewAdded(data);

+            }

+        });

+

+        base.tree.bind("select_node.jstree", function(e, data) {

+            if (v_selectedNode == data.node.id) {

+                data.instance.deselect_node(data.node);

+                v_selectedNode = "";

+            } else {

+                v_selectedNode = data.node.id;

+            }

+        });

+

+        base.tree.bind("redraw.jstree", function(e, data) {

+            document.getElementById(base.id).style.height = "auto";

+            document.getElementById(base.id).style.width = "auto";

+        });

+

+        base.openNodes();

+

+        base.tree.bind("after_open.jstree after_close.jstree", function(e, data) {

+            base.parent.refreshConnections(v_this);

+            document.getElementById(base.id).style.height = "auto";

+            document.getElementById(base.id).style.width = "auto";

+            base.saveOpenNodes();

+        });

+

+        base.tree.bind("ready.jstree", function(e, data) {

+            p_callback(true);

+        });

+    };

+

+    ///////////////////// HANDLING EVENTS //////////////////////////////

+

+    base.copyEditor = function() {

+        base.parent.copyViewEditor(base.viewmodel.getClass(), base.viewmodel.getCustomData());

+    };

+

+    base.treeSlid = function() {

+        if (base.isVisible) {

+            for (var i = 0; i < viewConnections.length; ++i) {

+                viewConnections[i].multiple = false;

+                viewConnections[i].style = "horizontal";

+            }

+        } else {

+            for (var i = 0; i < viewConnections.length; ++i) {

+                viewConnections[i].multiple = true;

+                viewConnections[i].style = "vertical";

+            }

+        }

+        base.refreshConnections();

+    };

+

+    base.editorDeleted = function() {

+        base.parent.editorDeleted("View", v_this);

+    };

+

+    base.getClasses = function(p_callback) {

+        base.parent.getViewClasses(p_callback);

+    };

+

+    ///////////////////// CHECKING OWN EVENTS //////////////////////////////

+

+    function isViewModelConnection(node, parent) {

+        return node.text === "View connection point" && base.jsTreeUtils.getDepth(parent, base.tree) === 1 && base.jsTreeUtils.getIndexOfNode(parent, base.tree) === 0;

+    }

+

+    function isAllowedViewConnection(node, parent, pos) {

+        if (node.text === "Child of ..." && !base.jsTreeUtils.isNodeFromTree(node, base.tree) && base.jsTreeUtils.getDepth(parent, base.tree) === 1 && base.jsTreeUtils.getIndexOfNode(parent, base.tree) === 2) {

+            var id = base.viewmodel.wouldUseId(pos);

+            return !base.parent.wouldCreateACycle(node, id);

+        } else {

+            return false;

+        }

+    }

+

+    function isImportConnection(node, parent) {

+        return node.text === "Import into ..." && base.jsTreeUtils.getDepth(parent, base.tree) === 1 && base.jsTreeUtils.getIndexOfNode(parent, base.tree) === 2;

+    }

+

+    ///////////////////// HANDLING OWN EVENTS //////////////////////////////

+

+    function deleteNode(p_data) {

+        // we have to get the jquery node instead of the jstree node

+        var treeNode = base.tree.jstree("get_node", p_data);

+        var jqueryNode = $("#" + treeNode.id);

+        var index = jqueryNode.parent().children().index(jqueryNode[0]);

+

+        var path = base.jsTreeUtils.getPath(base.tree.jstree("get_node", treeNode.id)).path;

+

+        if (path.length > 1 && path[0] == 0) {

+            base.viewmodel.deleteViewModelIndexFromPosition(index);

+            base.tree.jstree("delete_node", p_data);

+            base.connectionDeleted(viewmodelConnections, index);

+            base.refreshConnections();

+        } else if (path.length > 1 && path[0] == 2) {

+            base.viewmodel.removeChildView(index);

+            var nodeToDelete = base.jsTreeUtils.getLastNodeIdFromPath(base.tree, [2, jqueryNode.parent().children().length - 1])

+            base.tree.jstree("delete_node", nodeToDelete);

+            base.connectionDeleted(viewConnections, index);

+            base.refreshConnections();

+        }

+        base.saveOpenNodes();

+        base.validate();

+    }

+

+    function viewModelAdded(data) {

+        base.tree.jstree("delete_node", data.node.id);

+

+        var index = data.position;

+        var viewModelIndex = base.parent.getConnectionInformation("VM_V", data.original.id);

+

+        var text = "ViewModel " + viewModelIndex;

+        base.tree.jstree("create_node", data.parent, text, data.position);

+        base.tree.jstree("open_node", data.parent);

+

+        base.viewmodel.addViewModelIndex(viewModelIndex, index);

+        base.connectionAdded(viewmodelConnections, index, new ViewmodelConnectionEndpoint([0, index], viewModelIndex));

+        base.refreshConnections();

+

+        base.validate();

+    }

+

+    function viewAdded(data) {

+        base.tree.jstree("delete_node", data.node.id);

+

+        var index = data.position;

+        var size = base.viewmodel.getChildIds().length;

+

+        var parentId = base.viewmodel.addChildView(index);

+        var oldParentId = base.parent.getConnectionInformation("V_V", {"treeId": data.original.id, "parentId": parentId, "type": "set"});

+

+        var text = "Child view " + size;

+        base.tree.jstree("create_node", data.parent, text, "last");

+        base.tree.jstree("open_node", data.parent);

+

+        base.connectionAdded(viewConnections, index, getViewEndpoint([2, index], parentId));

+        // the next line will invalidate the parentId if the connection was moved from a parent view, so this is the safest place we can do this

+        base.viewmodel.removeConnectedChild(oldParentId);

+        base.refreshConnections();

+

+        base.validate();

+    }

+

+    function connectionMoved(data) {

+        var path = base.jsTreeUtils.getPath(base.tree.jstree("get_node", data.original.id)).path;

+        if (path[0] == 0) {

+            viewmodelConnectionMoved(data);

+        } else if (path[0] == 2) {

+            viewConnectionMoved(data);

+        }

+    }

+

+    function viewmodelConnectionMoved(data) {

+        base.tree.jstree("delete_node", data.original.id);

+

+        var fromIndex = data.old_position;

+        var toIndex = data.position;

+

+        if (toIndex > fromIndex) {

+            --toIndex;

+        } else if (fromIndex > toIndex) {

+            --fromIndex;

+        }

+

+        if (fromIndex == toIndex) {

+            return;

+        }

+

+        base.viewmodel.connectionOrderChanged(fromIndex, toIndex);

+        base.connectionMoved(viewmodelConnections, fromIndex, toIndex);

+        base.refreshConnections();

+    }

+

+    function viewConnectionMoved(data) {

+        base.tree.jstree("delete_node", data.node.id);

+

+        var fromIndex = data.old_position;

+        var toIndex = data.position;

+

+        if (toIndex > fromIndex) {

+            --toIndex;

+        } else if (fromIndex > toIndex) {

+            --fromIndex;

+        }

+

+        if (fromIndex == toIndex) {

+            return;

+        }

+

+        base.viewmodel.childViewOrderChanged(fromIndex, toIndex);

+        base.connectionMoved(viewConnections, fromIndex, toIndex);

+        base.refreshConnections();

+    }

+

+    ///////////////////// HANDLING CONNECTIONS //////////////////////////////

+

+    function ViewmodelConnectionEndpoint(p_path, p_identifier) {

+        return new base.Endpoint(

+            p_path,

+            p_identifier,

+            "target",

+            "VM_V",

+            {

+                "stroke": "blue"

+            },

+            function(htmlObj) {

+                var offset = htmlObj.offset();

+                offset.top += htmlObj.height() / 2;

+                return offset;

+            }

+        );

+    }

+

+    function ViewConnectionEndpoint(p_path, p_identifier, p_multiple, p_style) {

+        var endpoint = new base.Endpoint(

+            p_path,

+            p_identifier,

+            "target",

+            "V_V",

+            {

+                "stroke": "green"

+            },

+            function(htmlObj) {

+                var offset = htmlObj.offset();

+                offset.top += htmlObj.height() / 2;

+                return offset;

+            }

+        );

+

+        endpoint.multiple = p_multiple;

+        endpoint.style = p_style;

+

+        endpoint.getOffsets = function() {

+            var htmlObj = $("#" + base.id);

+            var offset = htmlObj.offset();

+

+            var upper = mcopy(offset);

+            upper.left += htmlObj.width() / 2;

+

+            var lower = mcopy(offset);

+            lower.left += htmlObj.width() / 2;

+            lower.top += htmlObj.height();

+

+            return [upper, lower];

+        }

+

+        return endpoint;

+    }

+

+    var viewConnectionPoint = {

+        "getOffset": function() {

+            var htmlObj;

+

+            if (!base.isVisible) {

+                var id = base.id + "_Header";

+                htmlObj = $("#" + id);

+            } else {

+                var id = base.jsTreeUtils.getLastNodeIdFromPath(base.tree, [1]);

+                htmlObj = $("#" + id + "_anchor");

+            }

+

+            var offset = htmlObj.offset();

+            offset.left += htmlObj.width();

+            offset.top += htmlObj.height() / 2;

+            return offset;

+        },

+

+        "getZIndex": function() {

+            return base.zIndex + 1;

+        },

+

+        "isEnabled": function() {

+            return base.isEnabled;

+        },

+

+        "object": v_this

+    }

+

+    function getViewEndpoint(p_path, p_identifier) {

+        if (base.isVisible) {

+            return new ViewConnectionEndpoint(p_path, p_identifier, false, "horizontal");

+        } else {

+            return new ViewConnectionEndpoint(p_path, p_identifier, true, "vertical");

+        }

+    }

+

+    this.getEndpoint = function(identifier) {

+        if (identifier == base.viewmodel.getParentId()) {

+            return viewConnectionPoint;

+        } else {

+            return undefined;

+        }

+    };

+

+    this.getConnectionInformation = function(identifier) {

+        var parentId = base.viewmodel.getParentId();

+        if (identifier.type == "set" && base.tree.jstree("get_node", identifier.treeId)) {

+            base.viewmodel.setParentId(identifier.parentId);

+            return parentId;

+        } else if (identifier.type == "get" && identifier.parentId == base.viewmodel.getParentId()) {

+            return parentId;

+        } else {

+            return undefined;

+        }

+    };

+

+    this.getEndpoints = function() {

+        var list = [];

+        for (var i = 0; i < viewmodelConnections.length; ++i) {

+            list.push(viewmodelConnections[i]);

+        }

+        for (var i = 0; i < viewConnections.length; ++i) {

+            list.push(viewConnections[i]);

+        }

+        return list;

+    };

+}

+//# sourceURL=GuiEditor\Views\View_ViewEditor.js

diff --git a/htdocs/WebApplications/GuiEditor/Views/View_ViewModelContentEditor.js b/htdocs/WebApplications/GuiEditor/Views/View_ViewModelContentEditor.js
new file mode 100644
index 0000000..ce51328
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_ViewModelContentEditor.js
@@ -0,0 +1,142 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_ViewModelContentEditor_View(p_viewmodel, p_id) {
+
+    var base = new GuiEditor_BaseContentEditor_View(p_viewmodel, p_id);
+
+    var HTML_OF_TAB = '' +
+        '<li>' +
+            '<a {2}href="#{0}">{1}</a>' +
+            '<span class="ui-icon ui-icon-close">Remove Tab</span>' +
+        '</li>';
+
+    var HTML_OF_FILETABS = '<div id="{0}"></div>';
+
+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////
+
+    this.applicationCreated = function() {
+        base.applicationCreated();
+        setupCallbacks();
+    };
+
+    ///////////////////// HANDLING TABS AND PANELS //////////////////////////////
+
+    this.applicationFocused = base.applicationFocused;
+
+    function setupCallbacks() {
+        $("#" + base.viewId + "_Button_New").on("click", newTab);
+        $("#" + base.viewId + "_Button_Load").on("click", load);
+        $("#" + base.viewId + "_Button_LoadTemplate").on("click", loadTemplate);
+        $("#" + base.viewId + "_Button_Save").on("click", save);
+        $("#" + base.viewId + "_Button_SaveAs").on("click", saveAs);
+    }
+
+    ///////////////////// HANDLING EVENTS //////////////////////////////
+
+    function save() {
+        base.save(saveAs);
+    }
+
+    function saveAs() {
+        function viewmodelSaved(name, ok, id, existingId) {
+            if (!ok) {
+                alert("Failed to save viewmodel " + name);
+            } else {
+                base.changeTabName(name);
+                base.setEdited(false, id);
+                if (existingId != undefined) {
+                    $("a[href$=" + existingId + "]").next("span").click();
+                }
+            }
+        }
+
+        base.saveAs(base.viewmodel.viewmodelExists, base.viewmodel.saveViewmodelAs, "Viewmodel", viewmodelSaved);
+    }
+
+    function createTab(id, name, operation) {
+        if (operation == "exists") {
+            base.fileTabs.tabs("option", "active", $('a[href$=' + id + ']').parent().index());
+            return;
+        }
+
+        if (operation == "new") {
+            base.fileTabs.find(".ui-tabs-nav").first().append(HTML_OF_TAB.format(id, name, 'class="file-changed" '));
+        } else {
+            base.fileTabs.find(".ui-tabs-nav").first().append(HTML_OF_TAB.format(id, name, ""));
+        }
+        base.fileTabs.append(HTML_OF_FILETABS.format(id));
+
+        base.fileTabs.tabs("refresh");
+        base.fileTabs.tabs("option", "active", $("#" + base.viewId + "_Tabs > ul > li").last().index());
+    }
+
+    function newTab() {
+        base.viewmodel.newViewmodelContent(createTab);
+    }
+
+    function load() {
+        function gotViewmodelName(viewmodelName) {
+            base.viewmodel.loadViewmodelContent(viewmodelName, createTab);
+        }
+
+        function optionsArrived(options) {
+            var dialog = new ChoiceDialogWithButton(base.viewId, "GuiEditor_Dialog_LoadViewmodel", {
+                "header": "Select a viewmodel",
+                "text": "Please select a viewmodel from the table below.",
+                "choices": options,
+                "callback": gotViewmodelName,
+                "buttonHandler": deleteViewmodel,
+                "buttonText": "X",
+                "buttonStyle": "color: red;",
+                "closeOnButtonPress": true
+            });
+            dialog.open();
+        }
+
+        base.viewmodel.listViewmodels(optionsArrived);
+    }
+
+    function loadTemplate() {
+        function gotViewmodelName(viewmodelName) {
+            base.viewmodel.loadViewmodelTemplate(viewmodelName, createTab);
+        }
+
+        function optionsArrived(options) {
+            var dialog = new ChoiceDialog(base.viewId, "GuiEditor_Dialog_LoadViewmodel", {
+                "header": "Select a viewmodel",
+                "text": "Please select a viewmodel from the table below.",
+                "choices": options,
+                "callback": gotViewmodelName
+            });
+            dialog.open();
+        }
+
+        base.viewmodel.listViewmodelTemplates(optionsArrived);
+    }
+
+    function deleteViewmodel(viewmodelName) {
+        var text = "Are you sure your want to delete viewmodel " + viewmodelName + "?";
+
+        function viewmodelDeleted(ok, id) {
+            if (!ok) {
+                alert("Failed to delete viewmodel " + viewmodelName);
+            } else if (id != undefined) {
+                base.setEdited(true, id);
+            }
+            load();
+        }
+
+        var dialog = new ConfirmationDialog(base.viewId, "GuiEditor_Dialog_DeleteViewmodel", {
+            "header": "Delete viewmodel",
+            "text": text,
+            "callback": function() {
+                base.viewmodel.deleteViewmodel(viewmodelName, viewmodelDeleted);
+            }
+        });
+        dialog.open();
+    }
+}
+//# sourceURL=GuiEditor\Views\View_ViewModelContentEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/GuiEditor/Views/View_ViewModelEditor.js b/htdocs/WebApplications/GuiEditor/Views/View_ViewModelEditor.js
new file mode 100644
index 0000000..9327d68
--- /dev/null
+++ b/htdocs/WebApplications/GuiEditor/Views/View_ViewModelEditor.js
@@ -0,0 +1,434 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function GuiEditor_ViewModelEditor_View(p_viewModel, p_parentId, p_viewId, p_parent, p_desktopData) {

+    "use strict";

+

+    var base = new GuiEditor_BaseEditor_View(p_viewModel, p_parentId, p_viewId, p_parent, p_desktopData, this);

+    var v_requestTree = base.parent.getRequestTree();

+

+    var v_this = this;

+    var v_selectedNode = "";

+

+    var dataConnections = [];

+    var selectionConnections = [];

+

+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////

+

+    this.init = function(callback) {

+        base.init(callback, "GuiEditor_ViewmodelEditor", 250);

+

+        var dataPaths = base.viewmodel.getDataConnections();

+        for (var i = 0; i < dataPaths.length; ++i) {

+            var endpoint = new DataConnectionEndpoint([1, i], i);

+            dataConnections.push(endpoint);

+        }

+

+        var selectionsPaths = base.viewmodel.getSelectionConnections();

+        for (var i = 0; i < selectionsPaths.length; ++i) {

+            var endpoint = new SelectionConnectionEndpoint([2, i], i);

+            selectionConnections.push(endpoint);

+        }

+

+        base.validate();

+    };

+

+    this.destroy = base.destroy;

+    this.setDefaultZidx = base.setDefaultZidx;

+    this.setZidx = base.setZidx;

+    this.deletePressed = function() {

+        var node = base.tree.jstree("get_selected");

+        if (node.length > 0) {

+            deleteNode(node);

+        }

+    };

+

+    ///////////////////// GENERAL EDITOR VIEW FUNCTIONS //////////////////////////////

+

+    this.disabled = base.disabled;

+    this.isNodeFromTree = base.isNodeFromTree;

+    this.validate = base.validate;

+    this.search = base.search;

+

+    ///////////////////// VIEWMODEL EDITOR SPECIFIC FUNCTIONS //////////////////////////////

+

+    this.requestRenamed = function(p_path, name) {

+        var paths = base.viewmodel.requestRenamed(p_path, name);

+        for (var i = 0; i < paths.length; ++i) {

+            var nodeId = base.jsTreeUtils.expandPath(base.tree, paths[i]);

+            base.tree.jstree("rename_node", nodeId, name);

+        }

+        if (paths.length > 0) {

+            base.refreshConnections();

+        }

+    };

+

+    this.updatePaths = function(path, amount) {

+        var connectionsRemoved = base.viewmodel.updateConnections(path, amount);

+        if (connectionsRemoved.length > 0) {

+            for (var i = 0; i < connectionsRemoved.length; ++i) {

+                var obj = connectionsRemoved[i];

+                if (obj.type == "data") {

+                    base.connectionDeleted(dataConnections, obj.index);

+                } else {

+                    base.connectionDeleted(selectionConnections, obj.index);

+                }

+            }

+

+            setIdentifiers();

+

+            base.createTree(function() {

+                base.tree.jstree("open_all");

+                base.refreshConnections();

+            });

+

+            base.validate();

+        }

+    };

+

+    this.pathsMoved = base.viewmodel.pathsMoved;

+

+    this.selectionAddedInRequestTree = function(requestNodeId, parentId) {

+        var parent = base.tree.jstree("get_node", parentId);

+        if (base.jsTreeUtils.isNodeFromTree(parent, base.tree)) {

+            var data = {

+                "parent": parent,

+                "position": 0,

+                "original": {

+                    "id": requestNodeId

+                }

+            };

+            requestAdded(data, false);

+            return true;

+        } else {

+            return false;

+        }

+    };

+

+    ///////////////////// CREATING THE VIEW //////////////////////////////

+

+    base.fillHeader = function(header) {

+        base.addButtonToHeader(header, "_Button_Edit", "GuiEditor_EditorButtonLeft", "EDIT");

+        var labelText = document.createElement("label");

+        labelText.setAttribute("id", base.id + "_HeaderText");

+        labelText.setAttribute("class", "GuiEditor_ViewmodelEditorHeaderLabel");

+        header.appendChild(labelText);

+        base.addButtonToHeader(header, "_Button_Minimize", "GuiEditor_EditorButtonRight", " ");

+    };

+

+    base.createTree = function(p_callback) {

+        var data = base.viewmodel.getTreeData();

+        base.tree.jstree("destroy");

+        base.tree.jstree({

+            "core": {

+                "data": data,

+                "check_callback": function(operation, node, node_parent, node_position, more) {

+                    if (operation === "copy_node") {

+                        if (base.jsTreeUtils.isRoot(node_parent)) {

+                            return false;

+                        }

+                        return (base.jsTreeUtils.isNodeFromTree(node, v_requestTree) && isDataOrSelection(node_parent)) || (base.jsTreeUtils.isTheParentOfNode(node, node_parent, base.tree));

+                    } else {

+                        return true;

+                    }

+                },

+                "multiple": false,

+                "animation": false,

+                "worker": false

+            },

+            "plugins": ["contextmenu", "dnd"],

+            "contextmenu": {

+                "items": function($node) {

+                    return {

+                        "Delete": {

+                            "label": "Delete",

+                            "action": function(data) {

+                                deleteNode(data.reference)

+                            }

+                        }

+                    };

+                },

+                "select_node": false

+            },

+            "dnd": {

+                "always_copy": true

+            }

+        });

+

+        base.tree.bind("copy_node.jstree", function(e, data) {

+            if (v_requestTree.jstree("get_node", data.original.id)) {

+                requestAdded(data, true);

+            } else {

+                connectionMoved(data);

+            }

+        });

+

+        base.tree.bind("select_node.jstree", function(e, data) {

+            if (v_selectedNode == data.node.id) {

+                data.instance.deselect_node(data.node);

+                v_selectedNode = "";

+            } else {

+                v_selectedNode = data.node.id;

+            }

+        });

+

+        base.tree.bind("redraw.jstree", function(e, data) {

+            document.getElementById(base.id).style.height = "auto";

+            document.getElementById(base.id).style.width = "auto";

+        });

+

+        base.openNodes();

+

+        base.tree.bind("after_open.jstree after_close.jstree", function(e, data) {

+            base.refreshConnections();

+            document.getElementById(base.id).style.height = "auto";

+            document.getElementById(base.id).style.width = "auto";

+            base.saveOpenNodes();

+        });

+

+        base.tree.bind("ready.jstree", function(e, data) {

+            p_callback(true);

+        });

+

+        base.tree.bind("hover_node.jstree", function(e, data) {

+            var path = base.jsTreeUtils.getPath(base.tree.jstree("get_node", data.node.id)).path;

+            if (path.length == 2 && path[0] == 1) {

+                $("#"+data.node.id).prop("title", base.viewmodel.getDataPathString(path[1]));

+            } else if (path.length == 2 && path[0] == 2) {

+                $("#"+data.node.id).prop("title", base.viewmodel.getSelectionPathString(path[1]));

+            }

+        });

+    }

+

+    ///////////////////// HANDLING EVENTS //////////////////////////////

+

+    base.copyEditor = function() {

+        base.parent.copyViewmodelEditor(base.viewmodel.getClass(), base.viewmodel.getCustomData());

+    };

+

+    base.editorDeleted = function() {

+        base.parent.editorDeleted("Viewmodel", v_this);

+    };

+

+    base.getClasses = function(p_callback) {

+        base.parent.getViewmodelClasses(p_callback);

+    };

+

+    ///////////////////// CHECKING OWN EVENTS //////////////////////////////

+

+    function isDataOrSelection(node) {

+        return base.jsTreeUtils.getDepth(node, base.tree) === 1 && base.jsTreeUtils.getIndexOfNode(node, base.tree) > 0;

+    }

+

+    ///////////////////// HANDLING OWN EVENTS //////////////////////////////

+

+    function deleteNode(data) {

+        // we have to get the jquery node instead of the jstree node

+        var treeNode = base.tree.jstree("get_node", data);

+        var jqueryNode = $("#" + treeNode.id);

+        var index = jqueryNode.parent().children().index(jqueryNode[0]);

+

+        var path = base.jsTreeUtils.getPath(base.tree.jstree("get_node", treeNode.id)).path;

+        var parentIndex = path[0];

+

+        if (path.length !== 1) {

+            base.tree.jstree("delete_node", data);

+            if (parentIndex === 1) {

+                base.viewmodel.deleteDataPath(index);

+                base.connectionDeleted(dataConnections, index);

+            } else {

+                base.viewmodel.deleteSelectionPath(index);

+                base.connectionDeleted(selectionConnections, index);

+            }

+            setIdentifiers();

+            base.refreshConnections();

+            document.getElementById(base.id).style.height = "auto";

+            document.getElementById(base.id).style.width = "auto";

+        }

+        base.saveOpenNodes();

+        base.validate();

+    }

+

+    function requestAdded(data, deleteNeeded) {

+        if (deleteNeeded) {

+            base.tree.jstree("delete_node", data.node.id);

+        }

+

+        var index = data.position;

+        var pathobj = base.jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.original.id));

+        var requestPath = pathobj.path;

+        var requestStrPath = pathobj.strpath;

+

+        var text;

+        if (requestStrPath.lastIndexOf(".") === -1) {

+            text = requestStrPath;

+        } else {

+            text = requestStrPath.substr(requestStrPath.lastIndexOf(".") + 1);

+        }

+        base.tree.jstree("create_node", data.parent, text, data.position);

+        base.tree.jstree("open_node", data.parent);

+

+        var parentIndex = base.jsTreeUtils.getPath(base.tree.jstree("get_node", data.parent)).path[0];

+        if (parentIndex === 1) {

+            base.viewmodel.addDataPath(requestStrPath, requestPath, index);

+            base.connectionAdded(dataConnections, index, new DataConnectionEndpoint([1, index], index));

+        } else {

+            base.viewmodel.addSelectionPath(requestStrPath, requestPath, index);

+            base.parent.selectionAdded(requestPath);

+            base.connectionAdded(selectionConnections, index, new SelectionConnectionEndpoint([2, index], index));

+        }

+        setIdentifiers()

+        base.refreshConnections();

+

+        base.validate();

+    }

+

+    function connectionMoved(data) {

+        base.tree.jstree("delete_node", data.original.id);

+

+        var fromIndex = data.old_position;

+        var toIndex = data.position;

+

+        if (toIndex > fromIndex) {

+            --toIndex;

+        } else if (fromIndex > toIndex) {

+            --fromIndex;

+        }

+

+        if (fromIndex == toIndex) {

+            return;

+        }

+

+        var parentIndex = base.jsTreeUtils.getPath(base.tree.jstree("get_node", data.parent)).path[0];

+        if (parentIndex === 1) {

+            base.viewmodel.moveDataPath(fromIndex, toIndex);

+            base.connectionMoved(dataConnections, fromIndex, toIndex);

+        } else {

+            base.viewmodel.moveSelectionPath(fromIndex, toIndex);

+            base.connectionMoved(selectionConnections, fromIndex, toIndex);

+        }

+        setIdentifiers();

+        base.refreshConnections();

+

+        base.validate();

+    }

+

+    ///////////////////// HANDLING CONNECTIONS //////////////////////////////

+

+    function setIdentifiers() {

+        for (var i = 0; i < dataConnections.length; ++i) {

+            dataConnections[i].setIdentifier(i);

+        }

+        for (var i = 0; i < selectionConnections.length; ++i) {

+            selectionConnections[i].setIdentifier(i);

+        }

+    }

+

+    function RequestEndpoint(p_path, p_identifier, p_options, p_getList, p_type) {

+        var v_identifier = p_identifier;

+        var v_getList = p_getList;

+

+        var endpoint = new base.Endpoint(

+            p_path,

+            function() {

+                return v_getList()[v_identifier];

+            },

+            "target",

+            p_type,

+            p_options,

+            function(htmlObj) {

+                var offset = htmlObj.offset();

+                offset.top += htmlObj.height() / 2;

+                return offset;

+            }

+        );

+

+        endpoint.setIdentifier = function(identifier) {

+            v_identifier = identifier;

+        }

+

+        return endpoint;

+    }

+

+    function DataConnectionEndpoint(p_path, p_identifier) {

+        return new RequestEndpoint(

+            p_path,

+            p_identifier,

+            {},

+            base.viewmodel.getDataConnections,

+            "DR_VM"

+        );

+    }

+

+    function SelectionConnectionEndpoint(p_path, p_identifier) {

+        return new RequestEndpoint(

+            p_path,

+            p_identifier,

+            {

+                "stroke": "red",

+                "arrowHead": "source"

+            },

+            base.viewmodel.getSelectionConnections,

+            "SR_VM"

+        );

+    }

+

+    var viewConnectionPoint = {

+        "getOffset": function() {

+            var htmlObj;

+

+            if (!base.isVisible) {

+                var id = base.id + "_Header";

+                htmlObj = $("#" + id);

+            } else {

+                var id = base.jsTreeUtils.getLastNodeIdFromPath(base.tree, [0]);

+                htmlObj = $("#" + id + "_anchor");

+            }

+

+            var offset = htmlObj.offset();

+            offset.left += htmlObj.width();

+            offset.top += htmlObj.height() / 2;

+            return offset;

+        },

+

+        "getZIndex": function() {

+            return base.zIndex + 1;

+        },

+

+        "isEnabled": function() {

+            return base.isEnabled;

+        },

+

+        "object": v_this

+    }

+

+    this.getEndpoint = function(identifier) {

+        if (identifier == base.parent.getViewmodelIndex(v_this)) {

+            return viewConnectionPoint;

+        } else {

+            return undefined;

+        }

+    };

+

+    this.getConnectionInformation = function(identifier) {

+        if (base.tree.jstree("get_node", identifier)) {

+            return base.parent.getViewmodelIndex(v_this)

+        } else {

+            return undefined;

+        }

+    };

+

+    this.getEndpoints = function() {

+        var list = [];

+        for (var i = 0; i < dataConnections.length; ++i) {

+            list.push(dataConnections[i]);

+        }

+        for (var i = 0; i < selectionConnections.length; ++i) {

+            list.push(selectionConnections[i]);

+        }

+        return list;

+    };

+}

+//# sourceURL=GuiEditor\Views\View_ViewModelEditor.js

diff --git a/htdocs/WebApplications/RequestConsole/Main.js b/htdocs/WebApplications/RequestConsole/Main.js
new file mode 100644
index 0000000..6229726
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Main.js
@@ -0,0 +1,151 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+var WebApplications = WebApplications || [];

+

+WebApplications.push({'application': new RequestConsole_Application()});

+

+function RequestConsole_Application() {

+    "use strict";

+

+    var v_appBase = new WebAppBase();

+    var v_webAppModel;

+

+    var jsfiles = [];

+

+    var v_extension;

+    var v_framework;

+    var v_model;

+    var v_viewmodel;

+    var v_view;

+    var v_binder;

+

+    this.info = function() {

+        return {

+            defaultIcon: "WebApplications/RequestConsole/Res/main_icon.png",

+            defaultName: "DsRestAPI Console"

+        };

+    };

+

+    this.load = function(p_webAppModel, p_params, p_framework)  {

+        v_webAppModel = p_webAppModel;

+        v_framework = p_framework;

+

+        function appConfigLoaded(config) {

+            if (config.lastEditedApp != undefined) {

+                new JsImportFromConfigTask(config.lastEditedApp + '/AppConfig.json', v_webAppModel.getFileHandler()).taskOperation(function(ok, extension) {

+                    v_extension = extension;

+                    v_appBase.load(jsfiles, [], start, v_webAppModel.getFileHandler());

+                });

+            } else {

+                alert("Error, lastEditedApp missing from config, can't choose API.");

+            }

+        }

+

+        new MultipleDirectoryListTask(

+            [

+                "WebApplications/RequestConsole/Models",

+                "WebApplications/RequestConsole/Views",

+                "WebApplications/RequestConsole/ViewModels"

+            ],

+            v_webAppModel.getFileHandler()

+        ).taskOperation(function(ok, resources) {

+            jsfiles = resources.jsfiles;

+            v_webAppModel.loadAppConfig('CustomizableContent/RequestConsole/AppConfig.json', appConfigLoaded);

+        });

+    };

+

+    this.unload = function(webappUnloaded) {

+        function callback(exitApp) {

+            if (exitApp) { v_appBase.unload(destroy); }

+            webappUnloaded(exitApp);

+        }

+

+        v_view.unload(callback);

+    };

+

+    function destroy() {

+        v_view.destroy();

+        v_viewmodel.destroy();

+

+        v_model = undefined;

+        v_view = undefined;

+        v_viewmodel = undefined;

+        v_binder = undefined;

+    }

+

+    function start(p_callback) {

+        v_model = new RequestConsole_Model(v_webAppModel, v_framework, v_extension);

+        v_viewmodel = new RequestConsole_ViewModel(v_model);

+        v_view = new RequestConsole_View(v_viewmodel, "TSGuiFrameworkMain", "RequestConsole_MainView");

+        v_binder = new RequestConsole_Binder(v_viewmodel, v_view);

+        v_viewmodel.setBinder(v_binder);

+

+        function callback(ok, data) {

+            if (ok) {

+                v_view.applicationCreated();

+                v_binder.fullRefresh();

+            } else {

+                alert(data);

+            }

+            if (typeof p_callback === "function") {

+                p_callback();

+            }

+        }

+

+        function setupLoaded() {

+            v_viewmodel.setSetup(v_model.getSetup());

+            var taskList = new SyncTaskList([new GenericTask(v_viewmodel.init), new GenericTask(v_view.init)], callback);

+            taskList.taskOperation();

+        }

+

+        var config = v_webAppModel.getAppConfig();

+        v_webAppModel.getSetupModel().setSetupDirectory(config.lastEditedApp + '/Setups');

+        if (config.lastEditedSetup != undefined) {

+            v_model.switchSetup(config.lastEditedSetup, setupLoaded);

+        } else {

+            v_model.newSetup();

+            setupLoaded();

+        }

+    }

+}

+

+function RequestConsole_Binder(p_viewModel, p_view) {

+    "use strict";

+

+    var v_viewmodel = p_viewModel;

+    var v_view = p_view;

+    var v_this = this;

+

+    this.fullRefresh = function() {

+        v_view.getRequestEditorView().destroy();

+        v_view.getRequestEditorView().fullRefresh();

+        v_view.updateSetupName();

+    };

+

+    this.selectionOrFilterChanged = function(p_path, p_selection, p_filter, p_rangeFilter, p_writableInfo, p_GetOrSetData) {

+        v_view.getRequestEditorView().selectionOrFilterChanged(p_path, p_selection, p_filter, p_rangeFilter, p_writableInfo, p_GetOrSetData);

+    };

+    

+    this.modelChanged = function() {

+        v_viewmodel.saveState();

+        v_view.getRequestEditorView().getCodeEditorView().refresh(true);

+    }

+    

+    this.responseArrived = function() {

+        v_view.refreshResponseDisplays();

+    }

+

+    this.notifyChange = function(aChangeText) {

+        function responseArrived()

+        {

+            v_this.fullRefresh();

+            v_this.modelChanged();

+        }

+        v_viewmodel.saveState(aChangeText);

+        v_viewmodel.sendRequest(responseArrived);

+    }

+}

+//# sourceURL=RequestConsole\Main.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/RequestConsole/Models/Model.js b/htdocs/WebApplications/RequestConsole/Models/Model.js
new file mode 100644
index 0000000..5b00ff4
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Models/Model.js
@@ -0,0 +1,184 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function RequestConsole_Model(p_webAppModel, p_framework, p_extension) {

+    "use strict";

+

+    var v_baseModel = p_webAppModel;

+    var v_setupModel = v_baseModel.getSetupModel();

+    var v_framework = p_framework;

+    var v_requestSchema;

+    var v_dsRestAPI;

+

+    if (v_baseModel.getAppConfig().lastEditedApp != undefined && window["DsRestAPI"] != undefined) {

+        v_dsRestAPI = new DsRestAPI(p_extension);

+    } else {

+        v_dsRestAPI = {"getHelp": function(callback) {callback(true, {"sources" : []});}};

+    }

+

+    v_baseModel.getFileHandler().loadFile('Utils/DsRestAPI/RequestSchema.json', function(ok, data) {

+        v_requestSchema = JSON.parse(data);

+    });

+

+    ///////////////////// SETUP HANDLING /////////////////////

+

+    this.resetSetupDir = function() {

+        v_setupModel.setSetupDirectory(v_baseModel.getAppConfig().appForListingSetups + '/Setups');

+    }

+    

+    this.newSetup = function() {

+        v_setupModel.newSetup();

+        changeLastEdited(undefined);

+        var setup = v_setupModel.getSetup();

+        fillDesktopSettings(setup);

+        return setup;

+    };

+

+    this.deleteSetup = function(name, callback) {

+        function setupDeleted(ok) {

+            var config = v_baseModel.getAppConfig();

+            if (ok && config.lastEditedSetup == name) {

+                changeLastEdited(undefined);

+            }

+            callback(ok)

+        }

+        v_setupModel.deleteSetup(name, setupDeleted);

+    };

+

+    this.switchSetup = function(p_setupName, p_setupLoaded) {

+        function setupLoaded(ok, setup, setupName) {

+            fillDesktopSettings(setup);

+            if (ok) {

+                changeLastEdited(setupName);

+            }

+            p_setupLoaded(ok, setup, setupName);

+        }

+        v_setupModel.loadSetup(p_setupName, setupLoaded, false);

+    };

+

+    this.saveSetup = v_setupModel.saveSetup;

+

+    this.saveSetupAs = function(setupName, callback) {

+        function setupSaved(ok) {

+            if (ok) {

+                changeLastEdited(setupName);

+            }

+            callback(ok);

+        }

+

+        v_setupModel.saveSetupAs(setupName, setupSaved);

+    };

+

+    this.listSetups = v_setupModel.listSetups;

+

+    this.setupExists = function(setupName, callback) {

+        v_setupModel.setupExists(setupName, callback);

+    };

+

+    function fillDesktopSettings(setup) {

+        var desktopData = setup.desktop.getData();

+        if (desktopData["HtmlEditor"] == undefined) {

+            desktopData["HtmlEditor"] = {};

+        }

+        if (desktopData["RequestEditor"] == undefined) {

+            desktopData["RequestEditor"] = {};

+        }

+    }

+

+    function changeLastEdited(lastEdited) {

+        var config = v_baseModel.getAppConfig();

+        config.lastEditedSetup = lastEdited;

+        //v_baseModel.saveAppConfig(config);

+    }

+

+    this.globalSetupSearch = v_setupModel.globalSetupSearch;

+

+    this.getSetup = v_setupModel.getSetup;

+

+    ///////////////////// RESOURCE HANDLING /////////////////////

+

+    function listJavascriptResources(locations, callback) {

+        new MultipleDirectoryListTask(locations, v_baseModel.getFileHandler()).taskOperation(function(ok, resources) {

+            callback(resources.jsfiles);

+        });

+    }

+

+    this.getViewUrl = function(name) {

+        return v_baseModel.getAppConfig().lastEditedApp + "/Views/" + name;

+    };

+

+    this.getViewmodelUrl = function(name) {

+        return v_baseModel.getAppConfig().lastEditedApp + "/ViewModels/" + name;

+    };

+

+    this.deleteFile = function(file, callback) {

+        v_baseModel.getFileHandler().delDirectory(file, callback);

+    };

+

+    ///////////////////// CONFIG HANDLING /////////////////////

+

+    this.getAppConfig = v_baseModel.getAppConfig;

+

+    this.setEditedApp = function(app, callback) {

+        var config = v_baseModel.getAppConfig();

+        config.lastEditedApp = app;

+        v_setupModel.setSetupDirectory(app + "/Setups");

+        //v_baseModel.saveAppConfig();

+        new JsImportFromConfigTask(app + '/AppConfig.json', v_baseModel.getFileHandler()).taskOperation(function(ok, extension) {

+            if (window["DsRestAPI"] != undefined) {

+                v_dsRestAPI = new DsRestAPI(extension);

+            }

+            callback(true);

+        });

+    };

+

+    this.listEditableApps = function(callback) {

+        var result = [];

+        var mainConfig = v_baseModel.getMainConfig();

+        for (var i = 0; i < mainConfig.availableApps.length; ++i) {

+            if (mainConfig.availableApps[i].directory == "WebApplications/CustomizableApp" && mainConfig.availableApps[i].params.customization != undefined) {

+                result.push(mainConfig.availableApps[i].params.customization);

+            }

+        }

+        callback(result);

+    };

+

+    this.listEditableConfigs = function(callback) {

+        var result = [{

+            "config": "CustomizableContent/MainConfig.json",

+            "schema": "CustomizableContent/MainConfigSchema.json"

+        }];

+        function filesArrived(data) {

+            for (var i = 0; i < data.length; ++i) {

+                if (data[i].contentType.endsWith("d")) {

+                    result.push({

+                        "config": data[i].fileName + "/AppConfig.json",

+                        "schema": data[i].fileName + "/AppConfigSchema.json"

+                    });

+                }

+            }

+            callback(result);

+        }

+        v_baseModel.getFileHandler().getDirectory("CustomizableContent", filesArrived);

+    };

+

+    ///////////////////// USEFUL FUNCTIONS FOR VIEWMODELS /////////////////////

+

+    this.getRequestSchema = function() {

+        return v_requestSchema;

+    }

+

+    this.getDesktopDataForRequestEditor = function() {

+        return v_setupModel.getSetup().desktop.getData()["RequestEditor"];

+    };

+

+    this.getDsRestAPI = function() {

+        return v_dsRestAPI;

+    };

+

+    this.getFileHandler = v_baseModel.getFileHandler;

+}

+

+//# sourceURL=RequestConsole\Models\Model.js

diff --git a/htdocs/WebApplications/RequestConsole/Res/getData.png b/htdocs/WebApplications/RequestConsole/Res/getData.png
new file mode 100644
index 0000000..1d1d60e
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Res/getData.png
Binary files differ
diff --git a/htdocs/WebApplications/RequestConsole/Res/getData18.png b/htdocs/WebApplications/RequestConsole/Res/getData18.png
new file mode 100644
index 0000000..5c84bf4
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Res/getData18.png
Binary files differ
diff --git a/htdocs/WebApplications/RequestConsole/Res/getDataS.png b/htdocs/WebApplications/RequestConsole/Res/getDataS.png
new file mode 100644
index 0000000..32ef24d
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Res/getDataS.png
Binary files differ
diff --git a/htdocs/WebApplications/RequestConsole/Res/main_icon.png b/htdocs/WebApplications/RequestConsole/Res/main_icon.png
new file mode 100644
index 0000000..04acb02
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Res/main_icon.png
Binary files differ
diff --git a/htdocs/WebApplications/RequestConsole/Res/setData.png b/htdocs/WebApplications/RequestConsole/Res/setData.png
new file mode 100644
index 0000000..210f66b
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Res/setData.png
Binary files differ
diff --git a/htdocs/WebApplications/RequestConsole/Res/setData18.png b/htdocs/WebApplications/RequestConsole/Res/setData18.png
new file mode 100644
index 0000000..25b18d7
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Res/setData18.png
Binary files differ
diff --git a/htdocs/WebApplications/RequestConsole/Res/setDataS.png b/htdocs/WebApplications/RequestConsole/Res/setDataS.png
new file mode 100644
index 0000000..d778573
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Res/setDataS.png
Binary files differ
diff --git a/htdocs/WebApplications/RequestConsole/ViewModels/ViewModel.js b/htdocs/WebApplications/RequestConsole/ViewModels/ViewModel.js
new file mode 100644
index 0000000..7d47129
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/ViewModels/ViewModel.js
@@ -0,0 +1,389 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function RequestConsole_ViewModel_Response() {

+    var v_data = undefined;

+    

+    this.getTextData = function(callback) {

+        if (v_data)

+            callback(JSON.stringify(v_data, null, 4));

+        else

+            callback("{}")

+    };

+

+    this.setTextData = function(data) {

+        v_data = mcopy(data);

+    };

+}

+

+function RequestConsole_ViewModel(p_model) {

+    "use strict";

+

+    var v_binder;

+    var v_setup;

+    var v_model = p_model;

+    var v_setupName;

+    var v_setupChanged = false;

+    var v_requestEditorViewModel = new RequestConsole_RequestEditor_ViewModel(v_model, this);

+    var v_responseEditorViewModel = new RequestConsole_ViewModel_Response(v_model, this);

+    var v_time = 0;

+    var v_lastCodeEditorChange = 0;

+    //var v_lastCodeEditorStateSave = 0;

+    setInterval(rebuildTreeBecauseOfCodeEditorChange, 100);

+

+    /////////// AUTO GUI //////////

+

+    var dataSourceUtils = new DataSourceUtils();   

+    var v_response;

+    var v_autogui_ViewModel = new CViewModel_AutoGUI({

+        "getResponseElement" : function() {

+            return dataSourceUtils.expandResponse(v_response, 0, [], [], v_setup.request.getData());

+        },

+        "getDsRestAPI": function() {

+            return v_model.getDsRestAPI();

+        }

+    });

+    

+    this.getHelp = function(callback) {

+        return v_help;

+    }

+

+    /////////// HISTORY ////////////

+

+    var v_history = [];

+    var v_nextHistoryEntry = 0;

+    var v_currentState;

+    var v_changes = {};

+    var v_historyEnabled = true;

+    var v_help;

+

+    var v_this = this;

+

+    ///////////////////// GETTER FOR SUBVIEWMODELS /////////////////////

+

+    this.getRequestEditorViewModel = function() {

+        return v_requestEditorViewModel;

+    };

+    

+    this.getResponseEditorViewModel = function() {

+        return v_responseEditorViewModel;

+    };

+

+    this.getAutoGuiViewModel = function() {

+        return v_autogui_ViewModel;

+    }

+

+    ///////////////////// GENERAL VIEWMODEL FUNCTIONS /////////////////////

+

+    this.init = function(p_callback) {

+        function viewmodelsInitilaized() {

+            // we need to load the setup as the config loads with it, and we need that to know the locations of views and viewmodels for customizable app

+            p_callback(true);

+            resetHistory();

+        }

+

+        var taskList = new TaskList([new GenericTask(v_requestEditorViewModel.init)], viewmodelsInitilaized);

+        taskList.taskOperation();

+        

+        function helpArrived(ok, help) {

+            if (ok) {

+                v_help = new HelpTreeBuilder(help).getHelpTree(true);

+            } else {

+            }

+        }

+        v_model.getDsRestAPI().getHelp(helpArrived);

+    };

+

+    this.destroy = function() {

+    }

+

+    this.setBinder = function(p_binder) {

+        v_binder = p_binder;

+        v_requestEditorViewModel.setBinder(p_binder);

+        v_autogui_ViewModel.setBinder(p_binder);

+    };

+

+    this.loadFile = v_model.getFileHandler().loadFile;

+    this.loadCss = v_model.getFileHandler().loadCss;

+    this.getAppConfig = v_model.getAppConfig;

+

+    ///////////////////// HANDLING SETUP AND APPLICATION CHANGED /////////////////////

+

+    this.modelChanged = function() {

+        if (v_binder)

+            v_binder.modelChanged();

+    }

+

+    this.isSetupChanged = function() {

+        return v_setupChanged;

+    };

+

+    this.setupChanged = function(how) {

+        v_setupChanged = true;

+        if (how != undefined && v_changes[how] == undefined) {

+            v_changes[how] = true;

+        }

+        v_binder.modelChanged();

+    };

+

+    this.setEditedApp = v_model.setEditedApp;

+

+    this.listEditableApps = function(callback) {

+        var result = [];

+

+        function appsListed(apps) {

+            for (var i = 0; i < apps.length; ++i) {

+                result.push({

+                    "value" : apps[i],

+                    "text" : apps[i]

+                });

+            }

+            callback(result);

+        }

+

+        v_model.listEditableApps(appsListed);

+    };

+

+

+    ///////////////////// SETUP HANDLING FUNCTIONS /////////////////////

+

+    this.newSetup = function() {

+        var setup = v_model.newSetup();

+        v_this.setSetup(setup);

+        v_binder.fullRefresh();

+        v_setupChanged = false;

+        resetHistory();

+        v_this.modelChanged();

+    };

+

+    this.deleteSetup = function(directory, callback) {

+        function setupDeleted(ok) {

+            if (ok && directory == v_setupName) {

+                v_setupName = undefined;

+            }

+            callback(ok);

+        }

+        v_model.deleteSetup(directory, setupDeleted);

+    };

+

+    this.switchSetup = function(selected, callback) {

+        function setupLoaded(ok, setup, setupName) {

+            v_this.setSetup(setup);

+            v_binder.fullRefresh();

+            if (ok) {

+                v_setupChanged = false;

+            }

+            v_this.modelChanged();

+            resetHistory();

+            callback(ok);

+        }

+        v_model.switchSetup(selected, setupLoaded);

+    };

+

+    this.listSetups = function(p_callback) {

+        function setupsLoaded(setups) {

+            var options = [];

+            for (var i = 0; i < setups.length; ++i) {

+                options.push({

+                    "value" : setups[i],

+                    "text" : setups[i]

+                });

+            }

+            p_callback(options);

+        }

+

+        v_model.resetSetupDir();

+        v_model.listSetups(setupsLoaded);

+    };

+

+    this.saveSetup = function(callback) {

+        v_model.saveSetup(callback);

+        v_setupChanged = false;

+    };

+

+    this.saveSetupAs = function(name, callback) {

+        function setupSaved(ok) {

+            if (ok) {

+                v_setupName = name;

+                v_setupChanged = false;

+            }

+            callback(ok);

+        }

+

+        v_model.saveSetupAs(name, setupSaved);

+    };

+

+    this.setupExists = v_model.setupExists;

+    this.globalSetupSearch = v_model.globalSetupSearch;

+

+    this.isCurrentlyEdited = function(name) {

+        return v_setupName == name;

+    };

+

+    this.isSaveable = function() {

+        return v_setupName != undefined;

+    };

+

+    this.getSetupName = function() {

+        return v_setupName;

+    };

+    

+    this.getTextData = function(callback) {

+        callback(JSON.stringify(v_setup.request.getData(), null, 4));

+    };

+

+    this.setTextData = function(data, changeText) {

+        v_setup.request.setData(JSON.parse(data));

+        this.setSetup(v_setup);

+        if (changeText) {

+            v_this.saveState(changeText);

+            v_binder.fullRefresh();

+        }

+        var nowdate = Date.now();

+        /*if (!v_lastCodeEditorChange && nowdate - v_lastCodeEditorStateSave > 500) {

+            v_binder.fullRefresh();

+            v_this.saveState("Text editor changes");            

+        }*/

+        v_lastCodeEditorChange = nowdate;

+    };

+

+    this.setSetup = function(setup) {

+        v_setup = setup;

+        v_setupName = setup.name;

+        v_requestEditorViewModel.setSetup(setup);

+        v_requestEditorViewModel.setDesktopData(v_model.getDesktopDataForRequestEditor());

+    }

+

+    ///////////////////// HISTORY /////////////////////

+

+    function rebuildTreeBecauseOfCodeEditorChange() {

+        var nowdate = Date.now();

+        if (v_lastCodeEditorChange && (nowdate - v_lastCodeEditorChange) > 500) {

+            var stateChanged = v_this.saveState("Text editor changes");

+            if (stateChanged)

+                v_binder.fullRefresh();

+            v_lastCodeEditorChange = 0;

+            //v_lastCodeEditorStateSave = nowdate;

+        }

+    }

+

+    function createState() {

+        var state = {};

+        state.request = mcopy(v_setup.request.getData());

+        state.viewmodels = mcopy(v_setup.viewmodels.getData());

+        state.views = mcopy(v_setup.views.getData());

+        state.imports = mcopy(v_setup.imports.getData());

+        state.desktop = mcopy(v_setup.desktop.getData());

+        state.html = v_setup.html.getData();

+        state.css = v_setup.css.getData();

+        return state;

+    }

+

+    function getStateAsString() {

+        var state = createState();

+        state.desktop = undefined;

+        return JSON.stringify(state);

+    }

+

+    function getChangeText(changes) {

+        var text = "";

+        var count = 0;

+        for (var key in changes) {

+            ++count;

+            text += key + ", "

+        }

+        text = text.slice(0, text.length - 2);

+

+        if (count == 0) {

+            text = "Minor changes";

+        }

+        return text;

+    }

+

+    this.saveState = function(changeText) {

+        var retval = false;

+        if (v_historyEnabled) {

+            var state = createState();

+            var stateString = getStateAsString();

+            if (stateString != v_currentState) {

+                if (v_history[v_nextHistoryEntry] != undefined) {

+                    v_history = v_history.slice(0, v_nextHistoryEntry);

+                }

+                if (changeText == undefined)

+                    state.text = getChangeText(v_changes);

+                else

+                    state.text = changeText;

+                v_history[v_nextHistoryEntry] = state;

+                ++v_nextHistoryEntry;

+                v_currentState = stateString;

+                retval = true;

+            }

+            v_changes = {};

+        }

+        return retval;

+    }

+

+    function resetHistory() {

+        v_nextHistoryEntry = 1;

+        var state = createState();

+        state.text = "History Beginning";

+        v_history = [state];

+        v_currentState = getStateAsString();

+    }

+

+    this.getHistory = function() {

+        return v_history;

+    };

+

+    this.getCurrentPositionInHistory = function() {

+        return v_nextHistoryEntry - 1;

+    }

+

+    this.historyEnabled = function(enabled) {

+        v_historyEnabled = enabled;

+    };

+

+    this.rewind = function(to) {

+        if (to < v_history.length) {

+            var state = v_history[to];

+            v_nextHistoryEntry = to + 1;

+            changeState(state);

+        }

+    };

+

+    function changeState(state) {

+        state = mcopy(state);

+        v_setup.request.setData(state.request);

+        v_setup.viewmodels.setData(state.viewmodels);

+        v_setup.views.setData(state.views);

+        v_setup.imports.setData(state.imports);

+        v_setup.desktop.setData(state.desktop);

+        v_setup.html.setData(state.html);

+        v_setup.css.setData(state.css);

+        v_this.setSetup(v_setup);

+        v_currentState = getStateAsString();

+        v_setupChanged = true;

+        v_binder.fullRefresh();

+        v_binder.modelChanged();

+    }

+    

+    this.sendRequest = function(refresh) {

+        function responseArrived(response) {

+            v_time = Date.now() - v_time;

+            v_responseEditorViewModel.setTextData(response);

+            v_response = response;

+            v_binder.responseArrived();

+            if (refresh)

+                refresh();

+        }

+        v_time = Date.now();

+        v_model.getDsRestAPI().getList(v_setup.request.getData(), responseArrived);

+    };

+    

+    this.getTime = function() {

+        return "Roundtrip time: " + v_time + " ms.";

+    };

+}

+//# sourceURL=RequestConsole\ViewModels\ViewModel.js

diff --git a/htdocs/WebApplications/RequestConsole/ViewModels/ViewModel_AutoGUI.js b/htdocs/WebApplications/RequestConsole/ViewModels/ViewModel_AutoGUI.js
new file mode 100644
index 0000000..85872be
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/ViewModels/ViewModel_AutoGUI.js
@@ -0,0 +1,96 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function CViewModel_AutoGUI(aViewModel, aOptions)

+{

+    "use strict";

+    /** private members */

+    var mViewModel;

+    var mBinder;

+    var mReponseDataPaths;

+

+    /** constructor */

+    mViewModel = aViewModel;

+    mReponseDataPaths = [];

+

+    /** public functions - Interface for parent */ 

+    this.setSelectionToControl = function(aSelection)

+    {};

+    

+    this.setReponseDataPath = function(aExpectedReponseDataIndex, aReponseDataPath)

+    {

+        mReponseDataPaths[aExpectedReponseDataIndex] = aReponseDataPath;

+    };

+    

+    this.setBinder = function(aBinder)

+    {

+        mBinder = aBinder;

+    };

+

+	/** public functions - Interface for views */ 

+    this.getResponseElement = function()

+    {

+        return mViewModel.getResponseElement(mReponseDataPaths[0]);

+    };

+    

+    this.command = function(aCklickedExpandedGetData, aOrigGetData, aValue, aIsContainer, aIsText)

+    {

+        function dataHasBeenSet(aData)

+        {

+            mBinder.notifyChange();

+        }

+        if (aCklickedExpandedGetData !== undefined && aOrigGetData.children !== undefined)

+        {

+            if (aOrigGetData.selection !== undefined)

+            {

+                if (aIsContainer)

+                    aOrigGetData.selection = undefined;

+                else if (aOrigGetData.selection[0] === aCklickedExpandedGetData.idxInList)

+                    aOrigGetData.selection = [];

+                else if (aCklickedExpandedGetData.idxInList != null)

+                    aOrigGetData.selection = [aCklickedExpandedGetData.idxInList];

+            }

+            else

+            {

+                if (aIsContainer)

+                    aOrigGetData.selection = [];

+                else if (aCklickedExpandedGetData.idxInList != null)

+                    aOrigGetData.selection = [aCklickedExpandedGetData.idxInList];

+            }

+            mBinder.notifyChange("Autogui changes");

+        }

+        else if (aCklickedExpandedGetData !== undefined && aOrigGetData.children === undefined && aIsText)

+        {

+            var newVal = prompt("Please enter new value", aValue);

+            if (newVal != null)

+            {

+                var lIndxList = [];

+                if (aCklickedExpandedGetData.idxInList !== undefined)

+                    lIndxList[0] = aCklickedExpandedGetData.idxInList;

+                mViewModel.getDsRestAPI().setData(dataHasBeenSet, aCklickedExpandedGetData.source, aCklickedExpandedGetData.element, newVal, aCklickedExpandedGetData.tp, aCklickedExpandedGetData.params, aCklickedExpandedGetData.ptcname, lIndxList);

+            }

+        }

+    };

+}

+

+CViewModel_AutoGUI.getHelp = function() {

+    return "This viewmodel is used with the same named view to visualize the response tree.";

+}

+

+CViewModel_AutoGUI.providesInterface = function() {

+    return ["getResponseElement", "command"];

+};

+

+CViewModel_AutoGUI.getCustomDataSchema = function() {

+    return {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "title": "Custom data for CViewModel_AutoGUI",

+        "type": "object",

+        "properties": {},

+        "additionalProperties": false

+    };

+};

+

+//# sourceURL=CustomizableApp\ViewModels\ViewModel_AutoGUI.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/RequestConsole/ViewModels/ViewModel_RequestEditor.js b/htdocs/WebApplications/RequestConsole/ViewModels/ViewModel_RequestEditor.js
new file mode 100644
index 0000000..adf9f32
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/ViewModels/ViewModel_RequestEditor.js
@@ -0,0 +1,338 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function RequestConsole_RequestEditor_ViewModel(p_model, p_parent) {

+    "use strict";

+

+    var v_model = p_model;

+    var v_parent = p_parent;

+    var dataSourceUtils = new DataSourceUtils();

+    var v_desktopData;

+    var v_binder;

+

+    var v_help;

+    var v_requests = [];

+    var v_requestBuilder = new DSHelpToRequest_manual();

+    v_requestBuilder.setRequest(v_requests);

+

+    var v_this = this;

+

+    ///////////////////// GENERAL FUNCTIONS /////////////////////

+

+    this.init = function(p_callback) {

+        function helpArrived(ok, help) {

+            if (ok) {

+                v_help = help;

+                p_callback(true);

+            } else {

+                p_callback(false, "Error getting help");

+            }

+        }

+

+        v_model.getDsRestAPI().getHelp(helpArrived);

+    };

+

+    this.setBinder = function(p_binder) {

+        v_binder = p_binder;

+    };

+

+    this.setSetup = function(setup) {

+        v_requests = setup.request.getData();

+        v_requestBuilder.setRequest(v_requests);

+    };

+    

+    this.modelChanged = function() {

+        if (v_binder)

+            v_binder.modelChanged();

+    }

+

+    ///////////////////// FUNCTIONS FOR VIEW VISUALIZATION /////////////////////

+

+    this.getHelp = function(refresh, toSort, elementIcon) {

+        function helpArrived(ok, p_help) {

+            if (ok) {

+                v_help = p_help;

+                var help = new HelpTreeBuilder(mcopy(v_help)).getHelpTree(toSort);

+                v_requestBuilder.setHelp(help);

+                var jsTreeData = dataSourceUtils.convertHelpToTreeDataArray(help.sources, elementIcon);

+                refresh(jsTreeData);

+            } else {

+                alert("Failed to get help");

+                refresh([]);

+            }

+        }

+        v_model.getDsRestAPI().getHelp(helpArrived);

+    };

+

+    this.getRawHelp = function() {

+        return v_help;

+    };

+

+    this.getRequestTree = function(refresh) {

+        var jsTreeData = dataSourceUtils.convertRequestToTreeDataArray(v_requests);

+        refresh(jsTreeData);

+    };

+

+    this.getFilterAsTree = function(p_path) {

+        var filter = v_requestBuilder.getFilterPart(p_path, []);

+        var treeData = [];

+        if (filter != undefined) {

+            traverseFilter(filter, treeData);

+        }

+        return treeData;

+    };

+

+    function traverseFilter(filter, treeData, paramName) {

+        var treeNode;

+        var treeNodeText = "";

+        if (paramName != undefined) {

+            treeNodeText = paramName + ": ";

+        }

+        if (filter.dataValue != undefined) {

+            treeNode = {"text": treeNodeText + filter.dataValue};

+            treeData.push(treeNode);

+        } else if (filter.request != undefined) {

+            treeNode = {"text": treeNodeText + filter.request.element, "children": []};

+            treeData.push(treeNode);

+            if (filter.request.params != undefined && filter.request.params.length > 0) {

+                for (var i = 0; i < filter.request.params.length; ++i) {

+                    traverseFilter(filter.request.params[i].paramValue, treeNode.children, filter.request.params[i].paramName);

+                }

+            }

+            if (filter.request.remapTo != undefined) {

+                traverseFilter(filter.request.remapTo, treeNode.children, "remapTo");

+            }

+        }

+    }

+

+    this.findSelectionsAndFilters = function() {

+        traverseRequest(v_requests, [], selectionOrFilterChanged);

+    };

+

+    function selectionOrFilterChanged(node, path) {

+        if (node.getData)

+            v_binder.selectionOrFilterChanged(path, node.getData.selection != undefined, node.getData.filter != undefined, node.getData.rangeFilter != undefined, node.getData.writableInfo != undefined, "getData");

+        else if (node.setData)

+            v_binder.selectionOrFilterChanged(path, node.setData.selection != undefined, node.setData.filter != undefined, node.setData.rangeFilter != undefined, node.setData.writableInfo != undefined, "setData");

+    }

+

+    function traverseRequest(list, path, processGetData) {

+        for (var i = 0; i < list.length; ++i) {

+            path.push(i);

+            processGetData(list[i], path);

+            if (list[i].getData && list[i].getData.children != undefined) {

+                traverseRequest(list[i].getData.children, path, processGetData);

+            } else if (list[i].setData && list[i].setData.children != undefined) {

+                traverseRequest(list[i].setData.children, path, processGetData);

+            }

+            path.pop();

+        }

+    }

+

+    this.selectionAdded = function(p_path) {

+        var request = v_this.getRequestFromPath(p_path);

+        if (request.getData.selection == undefined) {

+            request.getData.selection = [0];

+        }

+        selectionOrFilterChanged(request, p_path);

+        v_parent.setupChanged("Selection added");

+    };

+

+    this.setDesktopData = function(p_data) {

+        v_desktopData = p_data;

+    };

+

+    this.getDesktopData = function() {

+        return v_desktopData;

+    };

+

+    this.getRequestSchema = function() {

+        return v_model.getRequestSchema();

+    }

+

+    ///////////////////// FUNCTIONS FOR REQUEST EDITING /////////////////////

+

+    this.createRequest = function(p_helpPath, p_position, partialRefresh) {

+        var request = v_requestBuilder.createRequest(p_helpPath, p_position);

+        partialRefresh([p_position], dataSourceUtils.convertRequestToTreeDataArray([request])[0]);

+        v_parent.setupChanged('Request added: "' + request.getData.element + '"');

+    };

+

+    this.createEmptyRequest = function(p_position, partialRefresh) {

+        var request = v_requestBuilder.createEmptyRequest(p_position);

+        partialRefresh([p_position], dataSourceUtils.convertRequestToTreeDataArray([request])[0]);

+        v_parent.setupChanged("Empty request added");

+    };

+

+    this.addChildRequest = function(p_helpPath, p_requestPath, p_position, partialRefresh) {

+        var childRequest = v_requestBuilder.addChildRequest(p_helpPath, mcopy(p_requestPath), p_position);

+        p_requestPath.push(p_position);

+        partialRefresh(p_requestPath, dataSourceUtils.convertRequestToTreeDataArray([childRequest])[0]);

+        v_parent.setupChanged('Child request added: "' + childRequest.getData.element + '"');

+    };

+

+    this.addEmptyChildRequest = function(p_requestPath, p_position, partialRefresh) {

+        var childRequest = v_requestBuilder.addEmptyChildRequest(mcopy(p_requestPath), p_position);

+        p_requestPath.push(p_position);

+        partialRefresh(p_requestPath, dataSourceUtils.convertRequestToTreeDataArray([childRequest])[0]);

+        v_parent.setupChanged("Empty child request added");

+    };

+

+    this.copyRequest = function(p_path, partialRefresh) {

+        var childRequest = v_requestBuilder.copyRequest(mcopy(p_path));

+        p_path[p_path.length - 1] += 1;

+        partialRefresh(p_path, dataSourceUtils.convertRequestToTreeDataArray([childRequest])[0]);

+        v_parent.setupChanged('Request copied');

+    };

+

+    this.convertToSizeOf = function(p_path, refresh) {

+        var request = v_this.getRequestFromPath(p_path);

+        if (request.getData)

+            convertTo(request.getData, "sizeOf");

+        else {

+            convertTo(request.setData, "sizeOf");

+            request.getData = request.setData;

+            delete request.setData.content;

+            delete request.setData.tp;

+            delete request.setData;

+        }

+        refresh(p_path, "sizeOf");

+        v_parent.setupChanged('Request converted to "sizeOf"');

+    };

+

+    this.convertToSetData = function(p_path, refresh) {

+        var request = v_this.getRequestFromPath(p_path);

+        if (request.getData) {

+            request.setData = request.getData;

+            request.setData.content = "";

+            request.setData.tp = 0;

+            delete request.getData;

+        } else {

+            request.getData = request.setData;

+            delete request.setData.content;

+            delete request.setData.tp;

+            delete request.setData;

+        }

+        selectionOrFilterChanged(request, p_path);

+        v_parent.setupChanged('Request converted to "setData"');

+    };

+

+    this.convertToDataElementPresent = function(p_path, refresh) {

+        var request = v_this.getRequestFromPath(p_path);

+        if (request.getData)

+            convertTo(request.getData, "dataElementPresent");

+        else {

+            convertTo(request.setData, "dataElementPresent");

+            request.getData = request.setData;

+            delete request.setData.content;

+            delete request.setData.tp;

+            delete request.setData;

+        }

+        refresh(p_path, "dataElementPresent");

+        v_parent.setupChanged('Request converted to "dataElementPresent"');

+    };

+

+    this.matches = function(string, path) {

+        var request = v_requestBuilder.getRequestCopy(path);

+        return JSON.stringify(request).toLowerCase().indexOf(string) != -1;

+    };

+

+    function convertTo(request, p_element) {

+        var source = request.source;

+        var element = request.element;

+        var ptcname = request.ptcname;

+        var params = request.params;

+        if (params == undefined) {

+            params = [];

+        }

+

+        request.source = "DataSource";

+        request.element = p_element;

+        request.ptcname = undefined;

+        request.filter = undefined;

+        request.rangeFilter = undefined;

+        request.params = [{

+            "paramName": "Source",

+            "paramValue": source

+        }, {

+            "paramName": "Element",

+            "paramValue": element

+        }];

+        if (ptcname != undefined) {

+            request.params.push({

+                "paramName": "PTCName",

+                "paramValue": ptcname

+            })

+        }

+

+        for (var i = 0; i < params.length; ++i) {

+            request.params.push({

+                "paramName": "ParamName",

+                "paramValue": params[i].paramName

+            });

+            request.params.push({

+                "paramName": "ParamValue",

+                "paramValue": params[i].paramValue

+            });

+        }

+    }

+

+    this.isValidToAddRequest = v_requestBuilder.isValidToAddRequest;

+    this.isValidToCreateRequest = v_requestBuilder.isValidToCreateRequest;

+    this.isValidToMoveRequest = v_requestBuilder.isValidToMoveRequest;

+

+    this.moveRequest = function(p_fromPath, p_toPath, p_position) {

+        v_requestBuilder.moveRequest(p_fromPath, p_toPath, p_position);

+        v_parent.setupChanged("Request moved");

+    };

+

+    this.deleteRequest = function(data) {

+        v_requestBuilder.deleteRequest(data);

+        v_parent.setupChanged("Request deleted");

+    };

+

+    this.getRequest = v_requestBuilder.getRequest;

+    this.getRequestFromPath = v_requestBuilder.getRequestFromPath;

+    this.getRequestCopy = v_requestBuilder.getRequestCopy;

+

+    ///////////////////// FUNCTIONS FOR FILTER EDITING /////////////////////

+

+    this.getFilterPart = v_requestBuilder.getFilterPart;

+    this.getFilterPartCopy = v_requestBuilder.getFilterPartCopy;

+    this.addFilterPart = function(p_requestPath, p_filterPath, p_paramName) {

+        v_requestBuilder.addFilterPart(p_requestPath, p_filterPath, p_paramName);

+        v_parent.setupChanged("Filter added");

+    };

+    this.deleteFilterPart = function(p_requestPath, p_filterPath) {

+        v_requestBuilder.deleteFilterPart(p_requestPath, p_filterPath);

+        v_parent.setupChanged("Filter deleted");

+    };

+    this.convertFilterPartToRequest = function(p_requestPath, p_filterPath, p_helpPath) {

+        v_requestBuilder.convertFilterPartToRequest(p_requestPath, p_filterPath, p_helpPath);

+        v_parent.setupChanged("Filter type converted to request");

+    };

+    this.convertFilterPartToDataValue = function(p_requestPath, p_filterPath, p_newValue) {

+        v_requestBuilder.convertFilterPartToDataValue(p_requestPath, p_filterPath, p_newValue);

+        v_parent.setupChanged("Filter type converted to data value");

+    };

+    this.isValidToConvertFilterToRequest = v_requestBuilder.isValidToConvertFilterToRequest;

+    this.changeParamNameOfFilterRequest = function(p_requestPath, p_filterPath, p_paramName) {

+        v_requestBuilder.changeParamNameOfFilterRequest(p_requestPath, p_filterPath, p_paramName);

+        v_parent.setupChanged("Filter param name changed");

+    };

+    this.isValidToAddParamToFilterRequest = v_requestBuilder.isValidToAddParamToFilterRequest;

+    this.convertToDataElementPresentInFilter = function(p_requestPath, p_filterPath) {

+        var filter = v_requestBuilder.getFilterPart(p_requestPath, p_filterPath);

+        var params = filter.request.params;

+        convertTo(filter.request, "dataElementPresent");

+        for (var i = 0; i < filter.request.params.length; ++i) {

+            if (filter.request.params[i].paramValue.dataValue == undefined) {

+                filter.request.params[i].paramValue = {"dataValue": filter.request.params[i].paramValue};

+            }

+        }

+        v_parent.setupChanged('Filter element converted to "dataElementPresent"');

+    };

+}

+//# sourceURL=RequestConsole\ViewModels\ViewModel_RequestEditor.js

diff --git a/htdocs/WebApplications/RequestConsole/Views/View.css b/htdocs/WebApplications/RequestConsole/Views/View.css
new file mode 100644
index 0000000..9ed119a
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Views/View.css
@@ -0,0 +1,449 @@
+/* Global */

+

+TABLE {

+    width: 100%;

+    border: 0;

+}

+

+#RequestConsole_ElementEditor {

+    width: 405px;

+    height: 406px;

+}

+

+#RequestConsole_FilterElementEditor {

+    width: 380px;

+    height: 406px;

+}

+

+.ui-widget-content {

+    padding: 0px !important;

+}

+

+.form-control{

+    margin: 0px !important;

+}

+

+.ui-corner-all {

+    padding: 2px !important;

+}

+

+.property-selector {

+    width: 250px !important;

+}

+

+.form-control{

+    width: 145px !important;

+}

+

+.form-control > INPUT {

+    width: 145px !important;

+} 

+

+.ui-button  {

+    height: 30px !important;

+}

+

+

+#RequestConsole_Button_ClearRequest {

+    background-color: #d66;

+    color: white;

+    font-weight: bold;

+}

+

+#RequestConsole_Button_Send {

+    background-color: #d55;

+    border: 1px solid #d55;

+    color: white;

+    font-weight: bold;

+}

+

+#RequestConsole_Button_Send:hover {

+    background-color: #e99797;

+    border: 1px solid #e99797;

+}

+

+

+#RequestConsole_DsRestAPIHelp {

+    float: right;

+    font-size: 16px;

+    

+    background-color: #df8585;

+    color: white;

+}

+

+#RequestConsole_DsRestAPIHelp:hover {

+    background-color: #e99797;

+}

+

+#RequestConsole_ResponseDisplay {

+    /* width:99%; */

+    height:700px;

+    border:0px solid #eee;

+}

+

+/* Main tabs and title */

+

+#RequestConsole_Tabs {

+    height: calc(100% - 30px);

+}

+

+#RequestConsole_SetupName label {

+    font-size: 16px;

+    /*font-weight: bold;*/

+    display: inline-block;

+}

+

+#RequestConsole_GraphicalEditor {

+    width: calc(63% - 2px);

+    box-sizing: border-box;

+}

+

+#RequestConsole_CodeEditor {

+    width: calc(37% - 2px);

+    box-sizing: border-box;

+}

+

+#RequestConsole_GraphicalEditor,

+#RequestConsole_CodeEditor {

+    display: inline-block;

+}

+

+#RequestConsole_RequestEditorView {

+    height: calc(100% - 50px);

+}

+

+#RequestConsole_GraphicalEditor {

+    height: calc(100% - 0px);

+    overflow:hidden;

+}

+

+#RequestConsole_RequestEditorSplit {

+    height: calc(100% - 40px);

+}

+

+.splitter_panel .vsplitter {

+    background-color: #ccc;

+} 

+

+#RequestConsole_CodeEditor{

+    height: calc(100% - 0px);

+    top: 0px;

+    width: 40%;

+}

+

+/* Content editors */

+

+.file-changed  {

+    color: red !important;

+}

+

+/* Setup editor tab */

+

+#RequestConsole_Tabs .Aligner .ui-resizable-handle {

+    background-color: #aaa;

+    width: 5px;

+}

+

+.RequestConsole_Helpside {

+    width: 20%;

+}

+

+#RequestConsole_HelpTree {

+    width: 100%;

+    height: calc(100% - 50px);

+    overflow: auto;

+}

+

+#RequestConsole_RequestTree {

+    width: 100%;

+    padding-bottom: 100px;

+    background-color: #e5e5e5;

+}

+

+#RequestConsole_Playground {

+    width: 40%;

+    height: 100%;

+    display: inline-block;

+    position: relative;

+    overflow: auto;

+}

+

+/* legend */

+

+#RequestConsole_Legend {

+    position: absolute;

+    bottom: 0px;

+    right: 16px;

+    white-space: nowrap;

+    background-color: #e5e5e5;

+    opacity: 0.75;

+    z-index: 10000;

+    user-select: none;

+    cursor: default;

+}

+

+#RequestConsole_LegendToggle {

+    width: 20px;

+    height: 20px;

+    position: absolute;

+    bottom: 0px;

+    right: 0px;

+    background: #d66;

+    border-top-left-radius: 100%;

+}

+

+#RequestConsole_LegendToggle:hover {

+    background: #e99797;

+}

+

+#RequestConsole_Legend td:first-child {

+    text-align: center;

+}

+

+.RequestConsole_LegendCategory {

+    text-align: center;

+    font-weight: bold;

+}

+

+/* Coloring and sorting trees */

+

+li > a {

+    box-sizing: border-box;

+}

+

+#RequestConsole_RequestTree li.RequestConsole_NodeWithData > a,

+#RequestConsole_Legend .RequestConsole_NodeWithData {

+    border-left: 2px solid #d5d5d5;

+    border-right: 2px solid #d5d5d5;

+    border-top: 2px solid #d5d5d5;

+    border-bottom: 2px solid #d5d5d5;

+}

+

+#RequestConsole_RequestTree ul > li.RequestConsole_NodeWithSelection > a,

+#RequestConsole_Legend .RequestConsole_NodeWithSelection {

+    border-left: 2px solid red;

+}

+

+#RequestConsole_RequestTree ul > li.RequestConsole_NodeWithFilter > a,

+#RequestConsole_Legend .RequestConsole_NodeWithFilter {

+    border-top: 2px solid #9c5ccc;

+}

+

+#RequestConsole_RequestTree ul > li.RequestConsole_NodeWithRangeFilter > a,

+#RequestConsole_Legend .RequestConsole_NodeWithRangeFilter {

+    border-bottom: 2px solid green;

+}

+

+#RequestConsole_RequestTree ul > li.RequestConsole_NodeWithWritableInfo > a,

+#RequestConsole_Legend .RequestConsole_NodeWithWritableInfo {

+    border-right: 2px solid blue;

+}

+

+#RequestConsole_SortButton {

+    background-color: #c5c5c5;

+    height: 23px !important;

+    display: inline-block;

+    vertical-align: top;

+}

+

+#RequestConsole_SortButton:hover {

+    background-color: #999;

+    color: white;

+}

+

+#RequestConsole_SortButton[aria-pressed="true"] {

+    background-color: #4CAF50;

+    color: white;

+}

+

+#RequestConsole_HelpSearch {

+    width: calc(100% - 62px);

+    height: 20px;

+    display: inline-block;

+    vertical-align: top;

+}

+

+/* Setup editor's editors */

+

+DIV.RequestConsole_EditorHeader {

+    /*text-align: center;*/

+    cursor: move;

+    overflow: hidden;

+    white-space: nowrap;

+    display: block;

+    height: 16px;

+}

+

+DIV.RequestConsole_HtmlEditor DIV.RequestConsole_EditorHeader,

+.RequestConsole_HtmlEditorLegend {

+    background-color: #9ccc5c;

+}

+

+DIV.RequestConsole_ImportEditor DIV.RequestConsole_EditorHeader,

+.RequestConsole_ImportEditorLegend {

+    background-color: #cc9c5c;

+}

+

+DIV.RequestConsole_FilterEditor DIV.RequestConsole_EditorHeader,

+.RequestConsole_FilterEditorLegend {

+    background-color: #9c5ccc;

+}

+

+label.RequestConsole_HtmlEditorHeaderLabel,

+label.RequestConsole_FilterEditorHeaderLabel {

+    cursor: move;

+    height: 100%;

+    display: inline-block;

+    padding: 0px 4px;

+    white-space: nowrap;

+    overflow: hidden;

+    vertical-align: top;

+    font-size: 10px;

+}

+

+label.RequestConsole_HtmlEditorHeaderLabel {

+	/* 3 buttons, 2 35px, 1 20px, + 3*2 * 1 px border for the buttons = 96px + 2px for good luck */

+    width: calc(100% - 98px);

+}

+

+label.RequestConsole_ImportEditorHeaderLabel {

+    width: calc(100% - 28px);

+}

+

+label.RequestConsole_FilterEditorHeaderLabel {

+    /* 2 buttons, 1 35px, 2 20px, 2*2 * 1 px border for the buttons = 59px + 4px for good luck */

+    width: calc(100% - 83px);

+}

+

+.RequestConsole_HtmlEditor,

+.RequestConsole_FilterEditor {

+    background-color: #eee;

+    border: 1px solid #aaa;

+    position: absolute;

+    z-index: 800;

+    font-size: 10px;

+    width: auto;

+    height: auto;

+}

+

+button.RequestConsole_EditorButtonLeft,

+button.RequestConsole_EditorButtonRight {

+    background-color: #d66;

+    font-size: 10px;

+    font-weight: bold;

+    width: 35px;

+    height: 100%;

+    display: inline-block;

+    color: #fff;

+    border: 1px solid #ccc;

+    vertical-align: top;

+    padding: 0px;

+}

+

+button.RequestConsole_EditorButtonRight {

+    width: 20px;

+}

+

+button:active.RequestConsole_EditorButtonLeft,

+button:active.RequestConsole_EditorButtonRight {

+    background-color: #f22;

+}

+

+button:hover.RequestConsole_EditorButtonLeft,

+button:hover.RequestConsole_EditorButtonRight {

+    background-color: #e44;

+}

+

+.RequestConsole_Buttonbar {

+    margin: 0 0 5px 0;

+    /*width: 100%;*/

+    height: 22px;

+    position: absolute;

+    top: 0;

+    left: 0;

+}

+

+.RequestConsole_Disabled {

+    display: none;

+}

+

+.RequestConsole_Button_Left {

+    background-color: #df8585;

+    float: left;

+    border: 2px solid #df8585;

+    color: white;

+    height: 20px;

+}

+

+.RequestConsole_Button_Spacer {

+    width:5px;

+    float: left;

+    height: 23px;

+}

+

+.RequestConsole_Button_Right {

+    float: right;

+    background-color: #ccc;

+    border: 2px solid #ccc;

+    height: 23px;

+}

+

+.RequestConsole_Button_Left:hover {

+    background-color: #e99797;

+    border: 2px solid #e99797;

+}

+.RequestConsole_Button_Right:hover {

+    background-color: #999;

+    border: 2px solid #999;

+    color: white;

+}

+

+.RequestConsole_Titles {

+    font-weight: bold;

+    font-size: 14px;

+    background-color: #999;

+    border: 3px solid #999;

+    height: 23px;

+    text-align: center;

+    width: 100%;

+    box-sizing: border-box;

+}

+

+/* 3rd party customization */

+

+.dialog-table TD{

+    font-size: 14pt;

+}

+

+.ui-dialog .ui-state-error {

+    padding: .3em;

+}

+

+.ui-dialog {

+    white-space: nowrap;

+    z-index: 10000 !important;

+}

+

+.ui-widget-overlay {

+    z-index: 9900 !important;

+}

+

+.validateTips {

+    white-space: normal;

+}

+

+.validateSearch {

+    width: 60%;

+}

+

+.validateSearchButton, .validateSearchClear {

+    width: 20%;

+}

+

+.vakata-context {

+    z-index: 4000 !important;

+}

+

+#jstree-marker {

+    z-index: 4000 !important;

+}
\ No newline at end of file
diff --git a/htdocs/WebApplications/RequestConsole/Views/View.html b/htdocs/WebApplications/RequestConsole/Views/View.html
new file mode 100644
index 0000000..43ebb4e
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Views/View.html
@@ -0,0 +1,95 @@
+<style id="RequestConsole_WebAppStyle" type="text/css"></style>

+<div id="RequestConsole_SetupName">

+    <button id="RequestConsole_Button_SetApplication" class="RequestConsole_Button_Left">Change application</button>

+    <!--button id="RequestConsole_Button_New" class="RequestConsole_Button_Left">New</button-->

+    <button id="RequestConsole_Button_Load" class="RequestConsole_Button_Left">Load setup</button>

+    <div class="RequestConsole_Button_Spacer"></div>

+    <label id="RequestConsole_AppNameLabel"></label>

+    <label>-</label>

+    <label id="RequestConsole_SetupNameLabel"></label>

+    <a id="RequestConsole_DsRestAPIHelp" target="_blank" href="http://ttcn.ericsson.se/TitanSim/Help/StartUp_and_Use/Controlling_TitanSim/Using_TitanSim_Data_Source_REST_API.html">Help on DsRestAPI</a>

+</div>

+<div id="RequestConsole_Tabs">

+    <div id="RequestConsole_RequestEditorView">

+        <div class="line"></div>

+        <div id="RequestConsole_RequestEditorSplit" class="Aligner">

+            <div class="RequestConsole_Helpside Aligner_Horizontal_Content">

+                <div class="RequestConsole_Titles">Available Data Source Elements:</div>

+                <label for="RequestConsole_SortHelpTree" id="RequestConsole_SortButton">Sort</label>

+                <input id="RequestConsole_SortHelpTree" type="checkbox"></input>

+                <input id="RequestConsole_HelpSearch"></input>

+                <div id="RequestConsole_HelpTree"></div>

+            </div>

+            <div id="RequestConsole_Playground" class="Aligner_Horizontal_Content">

+                <div class="RequestConsole_Titles">Graphical Request Editor:</div>

+                <div id="RequestConsole_Buttonbar" class="RequestConsole_Buttonbar">

+                    <!--div class="RequestConsole_Button_Spacer"></div-->

+                    <button id="RequestConsole_Button_ClearRequest" class="RequestConsole_Button_Right">Clear</button>

+                    <button id="RequestConsole_Button_History" class="RequestConsole_Button_Right">History</button>

+                    <!--button id="RequestConsole_Button_GenerateRqFromHelp" class="RequestConsole_Button_Right">Generate full request from help</button-->

+                    <button id="RequestConsole_Button_AddRequest" class="RequestConsole_Button_Right">Add empty request</button>

+                </div>

+                <div id="RequestConsole_RequestTree"></div>

+                <div id="RequestConsole_Legend">

+                    <div id="RequestConsole_LegendToggle" title="Toggle Legend"></div>

+                    <table id="RequestConsole_LegendTable" class="visible">

+                        <col width="50px">

+                        </col>

+                        <col width="100px">

+                        </col>

+                        <tbody>

+                            <tr title="GetData request.">

+                                <td>

+                                    <img src="WebApplications/RequestConsole/Res/getData18.png" style="width:14px;height:14px;">

+                                </td>

+                                <td>getData</td>

+                            </tr>

+                            <tr title="SetData request.">

+                                <td>

+                                    <img src="WebApplications/RequestConsole/Res/setData18.png" style="width:14px;height:14px;">

+                                </td>

+                                <td>setData</td>

+                            </tr>

+                            <tr title="If the request has a selection, and it returns a lits, only the selected respponse's children will be queried.">

+                                <td class="RequestConsole_NodeWithData RequestConsole_NodeWithSelection"></td>

+                                <td>Selection</td>

+                            </tr>

+                            <tr title="Filters can be used to filter out some responses which do not match the filter. This can be used to return only specific elements in a list or to only query data when some condition is true.">

+                                <td class="RequestConsole_NodeWithData RequestConsole_NodeWithFilter"></td>

+                                <td>Filter</td>

+                            </tr>

+                            <tr title="Range filters are used to query only a part of a list. To control the range filters, specific viewmodels must be used.">

+                                <td class="RequestConsole_NodeWithData RequestConsole_NodeWithRangeFilter"></td>

+                                <td>Range Filter</td>

+                            </tr>

+                            <tr title="The writable info can be used to get writability of an element. This can be used for example to disable a label.">

+                                <td class="RequestConsole_NodeWithData RequestConsole_NodeWithWritableInfo"></td>

+                                <td>Writable Info</td>

+                            </tr>

+                        </tbody>

+                    </table>

+                </div>

+            </div>

+            <div id="RequestConsole_CodeEditor" class="Aligner_Horizontal_Content"></div>

+        </div>

+    </div>

+    <table>

+        <tr>

+            <td style="text-align: left;" colspan="1">

+                <span id="RequestConsole_Time"></span>

+            </td>

+            <td style="text-align: right;" colspan="2">

+                <button id="RequestConsole_Button_Send">Send Request</button>

+            </td>

+        </tr>

+    </table>

+    <div id="RequestConsole_ResponseDisplay">

+    </div>

+    <table>

+        <tr>

+            <td colspan="2">

+                <div id="RequestConsole_Button_AutoGui"></div>

+            </td>

+        </tr>

+    </table>

+</div>
\ No newline at end of file
diff --git a/htdocs/WebApplications/RequestConsole/Views/View.js b/htdocs/WebApplications/RequestConsole/Views/View.js
new file mode 100644
index 0000000..06a66ab
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Views/View.js
@@ -0,0 +1,291 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function RequestConsole_View(p_viewModel, p_parentId, p_viewId) {

+    "use strict";

+

+    var HTML = "WebApplications/RequestConsole/Views/View.html";

+

+    var parentDiv = document.getElementById(p_parentId);

+    var v_parentId = p_parentId;

+    var v_viewId = p_viewId;

+    var v_viewmodel = p_viewModel;

+    var v_this = this;

+

+    var v_requestEditorView = new RequestConsole_RequestEditor_View(v_viewmodel, v_this);

+    var v_responseDisplay = new CView_CodeEditor([p_viewModel.getResponseEditorViewModel()], 'RequestConsole_ResponseDisplay_', 'RequestConsole_ResponseDisplay', {"editorType": "json", "formatAllowed": true, "headerText": "Response text:"});

+    var v_autoGuiView = new CAutoGuiView([v_viewmodel.getAutoGuiViewModel()], "autogui", "RequestConsole_Button_AutoGui");

+    var v_focused_obj;

+

+    ///////////////////// GETTER FOR SUBVIEWS //////////////////////////////

+

+    this.getRequestEditorView = function() {

+        return v_requestEditorView;

+    };

+    

+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////

+

+    this.init = function(p_callback) {

+        var mainDiv = document.createElement("div");

+        mainDiv.setAttribute("id", v_viewId);

+        parentDiv.appendChild(mainDiv);

+

+        function htmlLoaded(ok, data) {

+            if (ok) {

+                $("#" + v_viewId).append(data);

+                $("#" + v_viewId).on("keydown", keyPressed);

+                $("#" + v_viewId).trigger("resize");

+                $("#RequestConsole_WebAppStyle").load("WebApplications/RequestConsole/Views/View.css", function() {

+                    v_this.toggleButtons(false);

+                    p_callback(true);

+                });

+            } else {

+                p_callback(false, "Error loading " + HTML);

+            }

+        }

+

+        v_viewmodel.loadFile(HTML, htmlLoaded);

+    };

+

+    function onWindowResize(event) {

+        if (event.target == window) {

+            $("#RequestConsole_MainView").height(ViewUtils.getSuggestedHeight("RequestConsole_MainView"));

+        }

+    }

+

+    this.applicationCreated = function() {

+        v_requestEditorView.applicationCreated();

+        $("#RequestConsole_Button_New").on("click", newSetup);

+        $("#RequestConsole_Button_Load").on("click", switchSetup);

+        $("#RequestConsole_Button_History").on("click", showHistory);

+        $("#RequestConsole_Button_SetApplication").on("click", changeApplication);

+        $("#RequestConsole_LegendToggle").on("click", function() {

+            $("#RequestConsole_LegendTable").toggleClass("hidden");

+        });

+        $("#RequestConsole_Button_Send").on('click', sendRequest);

+        $("#RequestConsole_Button_GenerateRqFromHelp").on('click', sendFullRequest);

+        $("#RequestConsole_Button_ClearRequest").on('click', clearRequest);

+        $(document).on("keydown", keyPressed);

+

+        $(window).on("resize", onWindowResize);

+        $("#RequestConsole_MainView").height(ViewUtils.getSuggestedHeight("RequestConsole_MainView"));

+

+        v_responseDisplay.applicationCreated();

+        v_responseDisplay.refresh(true);

+        v_autoGuiView.applicationCreated();

+    };

+

+    this.destroy = function() {

+        v_requestEditorView.destroy();

+        $("#" + v_viewId).remove();

+        $(document).off("keydown", keyPressed);

+        $(window).off("resize", onWindowResize);

+    };

+

+    this.unload = function(p_callback) {

+        if (v_viewmodel.isSetupChanged() == true && v_viewmodel.getAppConfig().confirmExit == true) {

+            var exitDialog = new ExitDialog(v_viewId, "RequestConsole_Dialog_Exit", {

+                "header": "Exit RequestConsole",

+                "text": "Do you wish to save changes before leaving?",

+                "callback": function(exit, save) {

+                    p_callback(exit);

+                }

+            });

+            exitDialog.open();

+        } else {

+            p_callback(true);

+        }

+    };

+

+    this.refreshResponseDisplays = function() {

+        v_responseDisplay.refresh(true);

+        v_autoGuiView.refresh(true);

+        document.getElementById("RequestConsole_Time").innerHTML = v_viewmodel.getTime();

+    }

+

+    ///////////////////// EVENT HANDLING FUNCTIONS //////////////////////////////

+

+    function keyPressed(event) {

+        if(event.keyCode === 46 && v_focused_obj != undefined && v_focused_obj.deletePressed != undefined) {

+            v_focused_obj.deletePressed();

+        }

+    }

+

+    function newSetup() {

+        v_this.toggleButtons(false);

+        v_viewmodel.newSetup();

+        v_this.updateSetupName();

+        v_focused_obj = undefined;

+    }

+

+    function deleteSetup(value) {

+        var text = "Are you sure your want to delete setup " + value + "?";

+        if (v_viewmodel.isCurrentlyEdited(value)) {

+            text += "<br><b>Warning! This is the currently edited setup<b>";

+        }

+

+        function setupDeleted(ok) {

+            if (!ok) {

+                alert("Failed to delete setup " + value);

+            }

+            v_this.updateSetupName();

+            switchSetup();

+        }

+

+        var dialog = new ConfirmationDialog(v_viewId, "RequestConsole_Dialog_DeleteSetup", {

+            "header": "Delete setup",

+            "text": text,

+            "callback": function() {

+                v_viewmodel.deleteSetup(value, setupDeleted);

+            }

+        });

+        dialog.open();

+    }

+

+    function switchSetup() {

+        function gotSetupName(p_setup) {

+            v_this.toggleButtons(false);

+            v_viewmodel.switchSetup(p_setup,

+                function callback(ok) {

+                    if (!ok) {

+                        alert("Loading setup failed");

+                    }

+                    v_this.updateSetupName();

+                    v_focused_obj = undefined;

+                }

+            );

+        }

+

+        function optionsArrived(options) {

+            var dialog = new ChoiceDialogWithButton(v_viewId, "RequestConsole_Dialog_LoadSetup", {

+                "header": "Select setup",

+                "text": "Please select a setup from the table below.",

+                "choices": options,

+                "callback": gotSetupName,

+                "buttonHandler": deleteSetup,

+                "buttonText": "X",

+                "buttonStyle": "color: red;",

+                "closeOnButtonPress": true,

+                "searchFunction": v_viewmodel.globalSetupSearch

+            });

+            dialog.open();

+        }

+

+        v_viewmodel.listSetups(optionsArrived);

+    }

+

+    function changeApplication() {

+        function gotApplicationName(p_application) {

+            v_viewmodel.setEditedApp(p_application, function() {

+                newSetup();

+            });

+        }

+

+        function optionsArrived(options) {

+            var dialog = new ChoiceDialog(v_viewId, "RequestConsole_Dialog_SetApplication", {

+                "header": "Select application",

+                "text": "Please select an application from the table below.",

+                "choices": options,

+                "callback": gotApplicationName

+            });

+            dialog.open();

+        }

+

+        v_viewmodel.listEditableApps(optionsArrived);

+    }

+

+    ///////////////////// USEFUL FUNCTION FOR VIEWS //////////////////////////////

+

+    this.toggleButtons = function(on) {

+        $(".RequestConsole_Button_Left").prop("disabled", !on);

+        $(".RequestConsole_Button_Right").prop("disabled", !on);

+    };

+

+    this.setFocusedObj = function(p_object) {

+        if (v_focused_obj != undefined) {

+            v_focused_obj.setDefaultZidx();

+        }

+        if (p_object != undefined) {

+            p_object.setZidx();

+        }

+        v_focused_obj = p_object;

+    };

+

+    this.updateSetupName = function() {

+        var config = v_viewmodel.getAppConfig();

+        if (config.lastEditedApp != undefined) {

+            document.getElementById("RequestConsole_AppNameLabel").innerHTML = config.lastEditedApp;

+        } else {

+            document.getElementById("RequestConsole_AppNameLabel").innerHTML = "... undefined application ...";

+        }

+        if (config.lastEditedSetup != undefined) {

+            document.getElementById("RequestConsole_SetupNameLabel").innerHTML = config.lastEditedSetup;

+        } else {

+            document.getElementById("RequestConsole_SetupNameLabel").innerHTML = "... unsaved setup ...";

+        }

+    };

+

+    ///////////////////// HISTORY //////////////////////////////

+

+    function HistoryElement(index, element) {

+        var v_index = index;

+        this.text = element.text;

+        this.callback = function() {

+            if (v_index != v_viewmodel.getCurrentPositionInHistory()) {

+                v_viewmodel.rewind(v_index);

+            }

+        };

+    }

+

+    function HistoryClass(history) {

+        var v_history = history;

+        this.getMenuElements = function() {

+            var contextItems = [];

+            for (var i = 0; i < v_history.length; ++i) {

+                contextItems.unshift(new HistoryElement(i, v_history[i]));

+            }

+            return contextItems;

+        };

+    }

+

+    function showHistory(event) {

+        v_viewmodel.historyEnabled(false);

+        var history = v_viewmodel.getHistory();

+        var contextMenuViewmodel = new HistoryClass(history);

+        var contextParentId = "RequestConsole_Buttonbar";

+        var contextId = "RequestConsole_History";

+        var customDataForContextMenu = {

+            "offset": $(this).offset()

+        };

+        var contextMenu = new CView_ContextMenu([contextMenuViewmodel], contextId, contextParentId, customDataForContextMenu);

+        contextMenu.applicationCreated();

+        $("#" + contextId).on("remove", function() {

+            v_viewmodel.historyEnabled(true);

+        });

+        $($("#" + contextId + " li")[history.length - v_viewmodel.getCurrentPositionInHistory() - 1]).css("color", "green");

+        $("#" + contextId + " li").css("padding-left", "65px");

+        $("#" + contextId + " li").css("background-color", "rgba(197,197,197,0.9)");

+    }

+    

+    function refreshScroll() {

+        $("html, body").animate({ scrollTop: $("#RequestConsole_Button_Send").offset().top - 4}, "fast");

+    }

+

+    function sendRequest() {

+        v_viewmodel.sendRequest(refreshScroll);

+    };

+    

+    function sendFullRequest() {

+        var request = DSHelpToRequest_full(v_viewmodel.getHelp());

+        v_viewmodel.setTextData(JSON.stringify(request), 'Request generation from full help');

+        v_viewmodel.modelChanged();

+    };

+

+    function clearRequest() {

+        v_viewmodel.setTextData('[]', 'Request cleared');

+        v_viewmodel.modelChanged();

+    };

+}

+//# sourceURL=RequestConsole\Views\View.js

diff --git a/htdocs/WebApplications/RequestConsole/Views/View_ElementEditor.js b/htdocs/WebApplications/RequestConsole/Views/View_ElementEditor.js
new file mode 100644
index 0000000..9bba7e4
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Views/View_ElementEditor.js
@@ -0,0 +1,319 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function RequestConsole_ElementEditor_View(p_viewmodel, p_parentId, p_viewId, p_parent) {

+    //"use strict";

+

+    var v_id = p_viewId;

+    var v_parentId = p_parentId;

+    var v_editorDiv;

+    var v_open = false;

+

+    var v_parentView = p_parent;

+    var v_viewmodel = p_viewmodel.getRequestEditorViewModel();

+    

+    

+

+    var v_path;

+    var v_request;

+

+    var v_customDataForEditor = {

+        "editorOptions": {

+            "disable_array_reorder": true,

+            "disable_edit_json": true,

+            "disable_collapse": true,

+            "no_additional_properties": true

+        },

+        "css": {

+            "z-index": 2000

+        },

+        "closeable": true,

+        "draggable": true,

+        "headerText": "Edit request"

+    }

+

+    var v_viewmodelForJSONEditor;

+    var editor;

+

+    var v_this = this;

+

+    function init() {

+        v_viewmodelForJSONEditor = new ElementEditorViewmodel(v_viewmodel.getRequestCopy(v_path), save, v_request);

+        

+        editor = new CView_JSONEditor([v_viewmodelForJSONEditor], v_id, v_parentId, v_customDataForEditor);

+

+        editor.applicationCreated();

+        ViewUtils.applyCss(v_customDataForEditor, v_id);

+

+        v_editorDiv = $("#" + v_id);

+        v_editorDiv.on('click', function(){

+            v_parentView.setFocusedObj(v_this);

+        });

+        v_editorDiv.on('dragstart', function(){

+            v_parentView.setFocusedObj(v_this);

+        });

+        v_editorDiv.on('remove', closed);

+        editor.refresh(true);

+

+        ViewUtils.jumpToEditor(v_id);

+    };

+

+    function closed() {

+        v_viewModel.findSelectionsAndFilters();

+        v_open = false;

+    }

+

+    this.setDefaultZidx = function() {

+        v_editorDiv.css("z-index" , 2500);

+    };

+

+    this.setZidx = function() {

+        v_editorDiv.css("z-index" , 3500);

+    };

+

+    this.deletePressed = function() {

+        v_parentView.deletePressed();

+    };

+

+    this.open = function(p_path, p_offset) {

+        if (v_open) {

+            v_this.close();

+        }

+        v_path = p_path;

+        v_request = v_viewmodel.getRequestFromPath(v_path);

+        v_customDataForEditor.offset = p_offset;

+        init();

+        v_open = true;

+    };

+

+    this.close = function() {

+        if (v_open) {

+            $("#" + v_id).remove();

+        }

+    };

+

+    function save(newRequest) {

+        var lGetOrSetData = "getData";

+        if (v_request.setData)

+            lGetOrSetData = "setData";

+        v_request[lGetOrSetData].source = newRequest.source;

+        v_request[lGetOrSetData].element = newRequest.element;

+        v_parentView.requestRenamed(v_path, newRequest.element);

+        v_request[lGetOrSetData].ptcname = newRequest.ptcname;

+        v_request[lGetOrSetData].params = newRequest.params;

+        v_request[lGetOrSetData].selection = newRequest.selection;

+        v_request[lGetOrSetData].selectionValues = newRequest.selectionValues;

+        v_request[lGetOrSetData].rangeFilter = newRequest.rangeFilter;

+        v_request[lGetOrSetData].writableInfo = newRequest.writableInfo;

+        v_request[lGetOrSetData].timeline = newRequest.timeline;

+        v_request[lGetOrSetData].content = newRequest.content;

+        v_request[lGetOrSetData].tp = newRequest.tp;

+

+        v_parentView.selectionOrFilterChanged(v_path, v_request[lGetOrSetData].selection != undefined, v_request[lGetOrSetData].filter != undefined, v_request[lGetOrSetData].rangeFilter != undefined, v_request[lGetOrSetData].writableInfo != undefined, lGetOrSetData);

+        v_viewmodel.modelChanged();

+    }

+}

+

+function ElementEditorViewmodel(p_data, p_save, p_request) {

+    var v_request = p_request;

+    var SETDATA_SCHEMA = {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "type": "object",

+        "title": "SetData request",

+        "properties": {

+            "source": {

+                "type": "string"

+            },

+            "ptcname": {

+                "type": "string"

+            },

+            "element": {

+                "type": "string"

+            },

+            "content": {

+                "type": "string"

+            },

+            "tp": {

+                "type": "integer",

+                "enum": [

+                  0,

+                  1,

+                  2,

+                  3,

+                  4,

+                  5,

+                  6,

+                  7,

+                  8,

+                  9,

+                  10,

+                  11

+                ],

+              "options": {

+                "enum_titles": [

+                    "filtered item",

+                    "integer",

+                    "float",

+                    "boolean",

+                    "charstring",

+                    "octetstring",

+                    "hexstring",

+                    "bitstring",

+                    "integerList",

+                    "floatList",

+                    "charstringList",

+                    "statusLED"

+                ]

+              }

+            },

+            "indxsInList": {

+                "type": "array",

+                "items": {

+                    "title": "index",

+                    "type": "integer"

+                },

+                "format": "table"

+            },

+            "params": {

+                "type": "array",

+                "items": {

+                    "title": "param",

+                    "type" : "object",

+                    "additionalProperties": false,

+                    "properties": {

+                        "paramName": {

+                            "type": "string"

+                        },

+                        "paramValue": {

+                            "type": "string"

+                        }

+                    },

+                    "required": [

+                        "paramName",

+                        "paramValue"

+                    ]

+                },

+                "format": "table"

+            }

+        },

+        "required": [

+            "source",

+            "element",

+            "content",

+            "tp"

+        ]

+    };

+

+    var GETDATA_SCHEMA = {

+        "$schema": "http://json-schema.org/draft-04/schema#",

+        "title": "Edit request",

+        "type": "object",

+        "properties": {

+            "source": {

+                "description": "The source",

+                "type": "string"

+            },

+            "element": {

+                "description": "The element",

+                "type": "string"

+            },

+            "ptcname": {

+                "description": "The ptc name",

+                "type": "string"

+            },

+            "params": {

+                "type": "array",

+                "format": "table",

+                "items": {

+                    "type": "object",

+                    "title": "Parameter",

+                    "properties": {

+                        "paramName" : {

+                            "type" : "string"

+                        },

+                        "paramValue" : {

+                            "type" : "string"

+                        }

+                    },

+                    "additionalProperties": false

+                },

+                "uniqueItems": true

+            },

+            "selection": {

+                "type": "array",

+                "format": "table",

+                "items": {

+                    "type": "integer",

+                    "minimum": "0",

+                    "title": "Selection item"

+                },

+                "uniqueItems": true

+            },

+            "selectionValues": {

+                "type": "array",

+                "format": "table",

+                "items": {

+                    "type": "string",

+                    "title": "Selected value"

+                }

+            },

+            "rangeFilter": {

+                "type": "object",

+                "properties": {

+                    "offset": {

+                        "type": "integer",

+                        "minimum": 0

+                    },

+                    "count": {

+                        "type": "integer",

+                        "minimum": 0

+                    }

+                },

+                "additionalProperties": false

+            },

+            "writableInfo": {

+                "type": "boolean",

+                "default": true

+            },

+            "timeline": {

+                "type": "object",

+                "properties": {

+                    "period": {

+                        "type": "number",

+                        "minimum": 0.0

+                    },

+                    "maxpoints": {

+                        "type": "integer",

+                        "minimum": 1

+                    },

+                    "since": {

+                        "type": "integer",

+                        "minimum": 0

+                    }

+                },

+                "additionalProperties": false,

+                "default": {}

+            }

+        },

+        "required": ["source", "element"]

+    };

+

+    var data = p_data;

+

+    this.getJSONData = function(callback) {

+        callback(data);

+    };

+

+    this.setJSONData = p_save;

+

+    this.getSchema = function() {

+        if (v_request && v_request.setData != undefined) {

+            return SETDATA_SCHEMA;

+        } else {

+            return GETDATA_SCHEMA;

+        }

+    };

+}

+//# sourceURL=RequestConsole\Views\View_ElementEditor.js

diff --git a/htdocs/WebApplications/RequestConsole/Views/View_FilterEditor.js b/htdocs/WebApplications/RequestConsole/Views/View_FilterEditor.js
new file mode 100644
index 0000000..031911a
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Views/View_FilterEditor.js
@@ -0,0 +1,331 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function RequestConsole_FilterEditor_View(p_viewmodel, p_parentId, p_viewId, p_parent, p_requestTree, p_helpTree) {
+
+    var v_viewmodel = p_viewmodel.getRequestEditorViewModel();
+    var v_parentId = p_parentId;
+    var v_id = p_viewId;
+    var v_parent = p_parent;
+    var v_editorDiv;
+    var v_open = false;
+
+    var v_tree;
+    var v_requestTree = p_requestTree;
+    var v_helpTree = p_helpTree;
+    var jsTreeUtils = new JsTreeUtils();
+
+    var v_requestPath;
+
+    var v_filterElementEditor = new RequestConsole_FilterElementEditor_View(v_viewmodel, "RequestConsole_Playground", "RequestConsole_FilterElementEditor", this);
+
+    var v_this = this;
+
+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////
+
+    function init() {
+        var html = '' +
+        '<div id="' + v_id + '" class="RequestConsole_FilterEditor">' +
+            '<div id="' + v_id + '_Header' + '" class="RequestConsole_EditorHeader">' +
+                '<button id="' + v_id + '_Button_Add" class="RequestConsole_EditorButtonLeft">Create</button>' +
+                '<label id="' + v_id + '_HeaderText" class="RequestConsole_FilterEditorHeaderLabel">Edit filter</label>' +
+                '<button id="' + v_id + '_Button_Context" class="RequestConsole_EditorButtonRight"><img src="WebApplicationFramework/Res/grip_white.png"></button>' +
+                '<button id="' + v_id + '_Button_Close" class="RequestConsole_EditorButtonRight">X</button>' +
+            '</div>' +
+            '<div id="' + v_id + '_Tree"></div>' +
+        '</div>';
+
+        $("#" + v_parentId).append(html);
+        v_tree = $("#" + v_id + "_Tree");
+        createTree();
+
+        v_editorDiv = $("#" + v_id);
+        v_editorDiv.draggable({
+            stop: function(event, ui) {
+                document.getElementById(v_id).style.height = "auto";
+                document.getElementById(v_id).style.width = "auto";
+            },
+            handle: "#" + v_id + "_Header",
+            containment: [$("#" + v_parentId).offset().left, $("#" + v_parentId).offset().top, 20000, 20000]
+        });
+        v_editorDiv.on('click', function(){
+            v_parent.setFocusedObj(v_this);
+        });
+        v_editorDiv.on('dragstart', function(){
+            v_parent.setFocusedObj(v_this);
+        });
+    };
+
+    this.destroy = function() {
+        v_editorDiv.remove();
+    };
+
+    this.setDefaultZidx = function() {
+        v_editorDiv.css("z-index", 800);
+    };
+
+    this.setFocusedObj = v_parent.setFocusedObj;
+
+    this.setZidx = function() {
+        v_editorDiv.css("z-index", 3000);
+    };
+
+    this.deletePressed = function() {
+        var selected = v_tree.jstree("get_selected")[0];
+        if (selected && selected.length != undefined) {
+            closeEditors();
+
+            var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", selected)).path;
+            filterPath.shift();
+            v_viewmodel.deleteFilterPart(v_requestPath, filterPath);
+            createTree();
+        }
+    };
+
+    ///////////////////// OPENING AND CLOSING THE EDITOR //////////////////////////////
+
+    this.open = function(p_path, p_offset) {
+        if (v_open) {
+            v_this.close();
+        }
+        v_requestPath = p_path;
+        init();
+        $("#" + v_id).offset(p_offset);
+        $("#" + v_id).offset(p_offset);
+        setupCallbacks();
+        v_open = true;
+    };
+
+    this.close = function() {
+        if (v_open) {
+            v_open = false;
+            closeEditors();
+            var request = v_viewmodel.getRequestFromPath(v_requestPath);
+            if (request.getData)
+                v_parent.selectionOrFilterChanged(v_requestPath, request.getData.selection != undefined, request.getData.filter != undefined);
+            else if (request.setData)
+                v_parent.selectionOrFilterChanged(v_requestPath, request.setData.selection != undefined, request.setData.filter != undefined);
+            $("#" + v_id).remove();
+        }
+    };
+
+    function closeEditors() {
+        v_filterElementEditor.close();
+    }
+
+    ///////////////////// CREATING AND REFRESHING THE TREE //////////////////////////////
+
+    function refreshTree() {
+        var data = v_viewmodel.getFilterAsTree(v_requestPath);
+        v_tree.jstree(true).settings.core.data = data;
+        v_tree.jstree("refresh");
+        v_tree.jstree("open_all");
+        v_viewmodel.modelChanged();
+    }
+
+    function createTree() {
+        var data = v_viewmodel.getFilterAsTree(v_requestPath);
+        v_tree.jstree("destroy");
+        v_tree = v_tree.jstree({
+            "core": {
+                "data": data,
+                "check_callback": function(operation, node, node_parent, node_position, more) {
+                    if (operation === "copy_node" && jsTreeUtils.isNodeFromTree(node, v_helpTree) && !jsTreeUtils.isRoot(node_parent)) {
+                        return dragFromHelpValidate(node.id, node_parent.id);
+                    } else if (operation === "copy_node" && jsTreeUtils.isNodeFromTree(node, v_requestTree) && !jsTreeUtils.isRoot(node_parent)) {
+                        var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", node.id)).path;
+                        return hasPrefix(v_requestPath, path);
+                    } else if (operation === "copy_node") {
+                        return false;
+                    } else {
+                        return true;
+                    }
+                },
+                "multiple": false,
+                "animation": false,
+                "worker": false
+            },
+            "plugins": ["contextmenu", "dnd"],
+            "dnd": {
+                "always_copy": true
+            },
+            "contextmenu": {
+                "items": function($node) {
+                    return {
+                        "Edit": {
+                            "label": "Edit filter",
+                            "action": function(data) {
+                                closeEditors();
+
+                                var offset = data.reference.offset();
+                                offset.left += data.reference.width();
+                                var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.reference)).path;
+                                filterPath.shift();
+                                v_filterElementEditor.open(v_requestPath, filterPath, offset, refreshTree);
+                                v_parent.setFocusedObj(v_filterElementEditor);
+                            },
+                            "separator_after": true
+                        },
+                        "Add": {
+                            "label": "Add param",
+                            "action": function(data) {
+                                closeEditors();
+
+                                var node = v_tree.jstree("get_node", data.reference);
+                                var filterPath = jsTreeUtils.getPath(node).path;
+                                var position = v_tree.jstree("get_children_dom", node).length;
+                                filterPath.shift();
+                                filterPath.push(position);
+                                if (v_viewmodel.isValidToAddParamToFilterRequest(v_requestPath, filterPath)) {
+                                    var paramName = prompt("New param name: ");
+                                    if (paramName != undefined) {
+                                        v_viewmodel.addFilterPart(v_requestPath, filterPath, paramName);
+                                        createTree();
+                                    }
+                                } else {
+                                    alert('Cannot add param to a dataValue');
+                                }
+                            }
+                        },
+                        "RemapTo": {
+                            "label": "Add remapTo",
+                            "action": function(data) {
+                                closeEditors();
+
+                                var node = v_tree.jstree("get_node", data.reference);
+                                var filterPath = jsTreeUtils.getPath(node).path;
+                                var position = v_tree.jstree("get_children_dom", node).length;
+                                filterPath.shift();
+                                filterPath.push(position);
+                                if (v_viewmodel.isValidToAddParamToFilterRequest(v_requestPath, filterPath)) {
+                                    var paramName = "remapTo";
+                                    v_viewmodel.addFilterPart(v_requestPath, filterPath, paramName);
+                                    createTree();
+                                } else {
+                                    alert('Cannot add param to a dataValue');
+                                }
+                            }
+                        },
+                        "Delete": {
+                            "label": "Delete",
+                            "action": function(data) {
+                                closeEditors();
+
+                                var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.reference)).path;
+                                filterPath.shift();
+                                v_viewmodel.deleteFilterPart(v_requestPath, filterPath);
+                                createTree();
+                            },
+                            "separator_after": true
+                        },
+                        "ChangeParamName": {
+                            "label": "Change param name",
+                            "action": function(data) {
+                                closeEditors();
+
+                                var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.reference)).path;
+                                filterPath.shift();
+                                var paramName = prompt("New param name: ");
+                                if (paramName != undefined) {
+                                    v_viewmodel.changeParamNameOfFilterRequest(v_requestPath, filterPath, paramName);
+                                    createTree();
+                                }
+                            }
+                        },
+                        "ConvertToElementPresent": {
+                            "label": "Convert to dataElementPresent",
+                            "action": function(data) {
+                                closeEditors();
+
+                                var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.reference)).path;
+                                filterPath.shift();
+                                if (v_viewmodel.isValidToAddParamToFilterRequest(v_requestPath, filterPath)) {
+                                    v_viewmodel.convertToDataElementPresentInFilter(v_requestPath, filterPath);
+                                }
+                                createTree();
+                            }
+                        }
+                    };
+                },
+                "select_node": true
+            }
+        });
+
+        v_tree.bind("hover_node.jstree", function(e, data) {
+            var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.node.id)).path;
+            filterPath.shift();
+            var string = JSON.stringify(v_viewmodel.getFilterPartCopy(v_requestPath, filterPath), null, 4);
+            $("#" + data.node.id).prop("title", string);
+        });
+
+        v_tree.bind("select_node.jstree", function (e, data) {
+            closeEditors();
+        });
+
+        v_tree.bind("after_close.jstree", function (e, data) {
+            v_tree.jstree("open_all");
+        });
+
+        v_tree.bind("redraw.jstree", function(e, data) {
+            document.getElementById(v_id).style.height = "auto";
+            document.getElementById(v_id).style.width = "auto";
+        });
+
+        v_tree.bind("copy_node.jstree", function(e, data) {
+            if (jsTreeUtils.isNodeFromTree(data.original, v_helpTree)) {
+                helpNodeCopied(data);
+            } else if (jsTreeUtils.isNodeFromTree(data.original, v_requestTree)) {
+                requestNodeCopied(data);
+            }
+        });
+
+        v_tree.bind("ready.jstree", function(e, data) {
+            v_tree.jstree("open_all");
+        });
+    }
+
+    ///////////////////// HANDLING EVENTS //////////////////////////////
+
+    function dragFromHelpValidate(p_helpId, p_filterId) {
+        var helpPath = jsTreeUtils.getPath(v_helpTree.jstree("get_node", p_helpId)).path;
+        var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", p_filterId)).path;
+        filterPath.shift();
+        return v_viewmodel.isValidToConvertFilterToRequest(v_requestPath, filterPath, helpPath)
+    }
+
+    function helpNodeCopied(data) {
+        closeEditors();
+        v_tree.jstree("delete_node", data.node.id);
+        var helpPath = jsTreeUtils.getPath(v_helpTree.jstree("get_node", data.original.id)).path;
+        var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.parent)).path;
+        filterPath.shift();
+        v_viewmodel.convertFilterPartToRequest(v_requestPath, filterPath, helpPath);
+        setTimeout(createTree, 0);
+    }
+
+    function requestNodeCopied(data) {
+        closeEditors();
+        v_tree.jstree("delete_node", data.node.id);
+        var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.original.id)).path;
+        var dataValue = "%Parent" + (path.length - 1) + "%";
+        var filterPath = jsTreeUtils.getPath(v_tree.jstree("get_node", data.parent)).path;
+        filterPath.shift();
+        v_viewmodel.convertFilterPartToDataValue(v_requestPath, filterPath, dataValue);
+        setTimeout(createTree, 0);
+    }
+
+    function setupCallbacks() {
+        $('#' + v_id + '_Button_Close').click(v_this.close);
+        $('#' + v_id + '_Button_Context').click(function() {
+            $("#" + jsTreeUtils.getNodeIdFromPath(v_tree, [0]) + " > a").contextmenu();
+        });
+        $('#' + v_id + '_Button_Add').click(function() {
+            closeEditors();
+            v_viewmodel.addFilterPart(v_requestPath, []);
+            createTree();
+        });
+    }
+}
+//# sourceURL=RequestConsole\Views\View_FilterEditor.js
\ No newline at end of file
diff --git a/htdocs/WebApplications/RequestConsole/Views/View_FilterElementEditor.js b/htdocs/WebApplications/RequestConsole/Views/View_FilterElementEditor.js
new file mode 100644
index 0000000..5749f27
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Views/View_FilterElementEditor.js
@@ -0,0 +1,178 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function RequestConsole_FilterElementEditor_View(p_viewmodel, p_parentId, p_viewId, p_parent) {
+    "use strict";
+
+    var v_id = p_viewId;
+    var v_parentId = p_parentId;
+    var v_editorDiv;
+    var v_open = false;
+
+    var v_parentView = p_parent;
+    var v_viewmodel = p_viewmodel;
+
+    var v_requestPath;
+    var v_filterPath;
+    var v_filter;
+    var v_refresh;
+
+    var v_customDataForEditor = {
+        "editorOptions": {
+            "disable_array_reorder": true,
+            "disable_edit_json": true,
+            "disable_collapse": true,
+            "no_additional_properties": true
+        },
+        "css": {
+            "z-index": 2000
+        },
+        "closeable": true,
+        "draggable": true,
+        "headerText": "Edit filter"
+    }
+
+    var v_viewmodelForJSONEditor;
+    var editor;
+
+    var v_this = this;
+
+    function init() {
+        v_viewmodelForJSONEditor = new FilterElementEditorViewmodel(v_viewmodel.getFilterPartCopy(v_requestPath, v_filterPath), save);
+        editor = new CView_JSONEditor([v_viewmodelForJSONEditor], v_id, v_parentId, v_customDataForEditor);
+
+        editor.applicationCreated();
+        ViewUtils.applyCss(v_customDataForEditor, v_id);
+
+        v_editorDiv = $("#" + v_id);
+        v_editorDiv.on('click', function(){
+            v_parentView.setFocusedObj(v_this);
+        });
+        v_editorDiv.on('dragstart', function(){
+            v_parentView.setFocusedObj(v_this);
+        });
+        v_editorDiv.on('remove', closed);
+        editor.refresh(true);
+
+        ViewUtils.jumpToEditor(v_id);
+    };
+
+    function closed() {
+        if (v_open) {
+            v_open = false;
+            v_refresh();
+        }
+    }
+
+    this.setDefaultZidx = function() {
+        v_editorDiv.css("z-index" , 2500);
+    };
+
+    this.setZidx = function() {
+        v_editorDiv.css("z-index" , 3500);
+    };
+
+    this.open = function(p_requestPath, p_filterPath, p_offset, p_refresh) {
+        if (v_open) {
+            v_this.close();
+        }
+        v_requestPath = p_requestPath;
+        v_filterPath = p_filterPath;
+        v_filter = v_viewmodel.getFilterPart(v_requestPath, v_filterPath);
+        v_refresh = p_refresh;
+        v_customDataForEditor.offset = p_offset;
+        init();
+        v_open = true;
+    };
+
+    this.close = function() {
+        if (v_open) {
+            $("#" + v_id).remove();
+        }
+    };
+
+    function save(newFilter) {
+        if (v_open) {
+            if (newFilter.dataValue != undefined) {
+                v_filter.dataValue = newFilter.dataValue;
+                v_filter.request = undefined;
+            } else if (newFilter.request != undefined) {
+                // preserve params
+                if (v_filter.request != undefined) {
+                    v_filter.request.source = newFilter.request.source;
+                    v_filter.request.element = newFilter.request.element;
+                    v_filter.request.ptcname = newFilter.request.ptcname;
+                } else {
+                    v_filter.request = newFilter.request;
+                }
+                v_filter.dataValue = undefined;
+            }
+        }
+    }
+}
+
+function FilterElementEditorViewmodel(p_data, p_save) {
+    var schema = {
+        "$schema": "http://json-schema.org/draft-04/schema#",
+        "title": "Edit filter",
+        "type": "object",
+        "oneOf": [
+            {
+                "title": "data value",
+                "type": "object",
+                "properties": {
+                    "dataValue": {
+                        "description": "A value",
+                        "type": "string",
+                        "default": "true"
+                    }
+                },
+                "required": ["dataValue"],
+                "additionalProperties": false
+            },
+            {
+                "title": "request",
+                "type": "object",
+                "properties": {
+                    "request": {
+                        "description": "A request that will be converted to a value during the filter evaluation",
+                        "type": "object",
+                        "properties": {
+                            "source": {
+                                "description": "The source",
+                                "type": "string"
+                            },
+                            "element": {
+                                "description": "The element",
+                                "type": "string"
+                            },
+                            "ptcname": {
+                                "description": "The ptc name",
+                                "type": "string"
+                            }
+                        },
+                        "required": ["source", "element"],
+                        "additionalProperties": false
+                    }
+                },
+                "required": ["request"],
+                "additionalProperties": false
+            }
+        ]
+    };
+
+    var data = p_data;
+
+    this.getJSONData = function(callback) {
+        callback(data);
+    };
+
+    this.setJSONData = p_save;
+
+    this.getSchema = function() {
+        return schema;
+    };
+}
+//# sourceURL=RequestConsole\Views\View_FilterElementEditor.js
diff --git a/htdocs/WebApplications/RequestConsole/Views/View_RequestEditor.js b/htdocs/WebApplications/RequestConsole/Views/View_RequestEditor.js
new file mode 100644
index 0000000..b53f0e7
--- /dev/null
+++ b/htdocs/WebApplications/RequestConsole/Views/View_RequestEditor.js
@@ -0,0 +1,618 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function RequestConsole_RequestEditor_View(p_viewModel, p_parent) {

+    "use strict";

+

+    var v_viewModel = p_viewModel.getRequestEditorViewModel();

+    var v_parent = p_parent;

+

+    var v_desktopData;

+    var v_helpTree;

+    var v_requestTree;

+    var v_elementEditor;

+    var v_filterEditor;

+    var v_codeEditor;

+    var v_checkDisabled = false;

+    var v_this = this;

+

+    var jsTreeUtils = new JsTreeUtils();

+    var v_requestSchema;

+    var validate;

+

+    ///////////////////// GENERAL VIEW FUNCTIONS //////////////////////////////

+

+    this.applicationCreated = function() {

+        v_requestSchema = v_viewModel.getRequestSchema();

+        validate = new Ajv({}).compile(v_requestSchema);

+

+        var aligner = new CView_Aligner([], "RequestConsole_RequestEditorSplit", undefined, {

+            "existing": true,

+            "resizable": true

+        });

+        aligner.applicationCreated();

+

+        v_desktopData = v_viewModel.getDesktopData();

+        v_helpTree = $("#RequestConsole_HelpTree");

+        v_requestTree = $("#RequestConsole_RequestTree");

+

+        v_elementEditor = new RequestConsole_ElementEditor_View(p_viewModel, "RequestConsole_Playground", "RequestConsole_ElementEditor", v_this);

+        v_filterEditor = new RequestConsole_FilterEditor_View(p_viewModel, "RequestConsole_Playground", "RequestConsole_FilterEditor", v_this, v_requestTree, v_helpTree);

+        v_codeEditor = new CView_CodeEditor([p_viewModel], 'RequestConsole_CodeEditor_', 'RequestConsole_CodeEditor', {"editorType": "json", "formatAllowed": true, "headerText": "Request As Text:"});

+        v_codeEditor.applicationCreated();

+        v_codeEditor.refresh(true);

+        v_codeEditor.onDataChanged(onCodeEditorDataChanged);

+        v_codeEditor.isValid = function(text) {

+            var data;

+            try {

+                data = JSON.parse(text);

+            } catch (e) {

+                return false;

+            }

+            if (data != undefined) {

+                var isValid = validate({"requests":data});

+                if (!isValid) {

+                    return false;

+                }

+                else {

+                    return true;

+                }

+            }

+        };

+

+        setupCallbacks();

+        v_viewModel.getHelp(createHelpJSTree, v_desktopData["sortHelp"], "WebApplications/RequestConsole/Res/getData.png");

+    };

+

+    function onCodeEditorDataChanged(value) {

+        if (value == "")

+        {

+            return "[]"

+        }

+        else

+            return value;

+    }

+

+    this.getCodeEditorView = function() {

+        return v_codeEditor;

+    };

+

+    this.setFocusedObj = function(p_object) {

+        v_parent.setFocusedObj(p_object);

+    };

+

+    this.setDefaultZidx = function() {};

+    this.setZidx = function() {};

+    this.deletePressed = function() {

+        var selected = v_requestTree.jstree("get_selected")[0];

+        if (selected != undefined) {

+            deleteNode(selected);

+        }

+    };

+

+    this.fullRefresh = function() {

+        v_desktopData = v_viewModel.getDesktopData();

+        function viewsInitialized() {

+            v_parent.toggleButtons(true);

+

+            $(document).on("keydown", toggleValidation);

+            $(document).on("keyup", toggleValidation);

+        }

+

+        var taskList = new TaskList([new GenericTask(createViewElements)], viewsInitialized);

+        taskList.taskOperation();

+    };

+

+    this.destroy = function() {

+        closeEditors();

+        $(document).off('dnd_move.vakata', helpToRequestDrag);

+        $(document).off('dnd_stop.vakata', helpToRequestDrop);

+        $(document).off('dnd_stop.vakata', requestToHelpDrop);

+        $(document).off("keydown", toggleValidation);

+        $(document).off("keyup", toggleValidation);

+        v_requestTree.jstree("destroy");

+    };

+

+    this.search = function(string) {

+        var nodes = $("#RequestConsole_RequestTree li");

+        for (var i = 0; i < nodes.length; ++i) {

+            var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", $(nodes[i]))).path;

+            if (v_viewModel.matches(string, path)) {

+                $(nodes[i]).addClass("found");

+            }

+        }

+    };

+

+    ///////////////////// INTERACTION WITH OUTHER VIEWS //////////////////////////////

+

+    this.getRequestTree = function() {

+        return v_requestTree;

+    };

+

+    this.requestRenamed = function(p_path, name) {

+        v_requestTree.jstree("rename_node", jsTreeUtils.getLastNodeIdFromPath(v_requestTree, p_path), name);

+    };

+

+    this.selectionAdded = function(path) {

+        v_viewModel.selectionAdded(path);

+    };

+

+    this.selectionOrFilterChanged = function(p_path, p_selection, p_filter, p_rangeFilter, p_writableInfo, p_getOrSetData) {

+        var id = jsTreeUtils.getNodeIdFromPath(v_requestTree, mcopy(p_path));

+        if (id !== false) {

+            $("#" + id).removeClass("RequestConsole_NodeWithData RequestConsole_NodeWithSelection RequestConsole_NodeWithFilter RequestConsole_NodeWithRangeFilter RequestConsole_NodeWithWritableInfo");

+            var hasData = false

+            if (p_selection) {

+                $("#" + id).addClass("RequestConsole_NodeWithSelection");

+                hasData = true;

+            }

+            if (p_filter) {

+                $("#" + id).addClass("RequestConsole_NodeWithFilter");

+                hasData = true;

+            }

+            if (p_rangeFilter) {

+                $("#" + id).addClass("RequestConsole_NodeWithRangeFilter");

+                hasData = true;

+            }

+            if (p_writableInfo) {

+                $("#" + id).addClass("RequestConsole_NodeWithWritableInfo");

+                hasData = true;

+            }

+            if (hasData) {

+                $("#" + id).addClass("RequestConsole_NodeWithData");

+            }

+            if (p_getOrSetData) {

+                var shiftString = "";

+                if (hasData)

+                    shiftString = "S";

+                $("#RequestConsole_RequestTree").jstree(true).set_icon(id, "WebApplications/RequestConsole/Res/" + p_getOrSetData + shiftString + ".png");

+            }

+        }

+    };

+

+    ///////////////////// CREATING VIEW ELEMENTS AND INTERACTIONS //////////////////////////////

+

+    function createViewElements(callback) {

+        v_viewModel.getRequestTree(function(data) {

+            createRequestJSTree(data, callback);

+        });

+    }

+

+    function createHelpJSTree(p_data) {

+        v_helpTree.jstree("destroy");

+        v_helpTree = v_helpTree.jstree({

+            "core": {

+                "data": p_data,

+                "check_callback" : function(operation, node, node_parent, node_position, more) {

+                     if (operation === "copy_node" || operation === "move_node") {

+                         return false;

+                     } else {

+                         return true;

+                     }

+                },

+                "multiple" : false,

+                "animation": false,

+                "worker": false

+            },

+            "plugins" : ["search", "dnd", "types"],

+            "search" : {

+                "show_only_matches": true

+            },

+            "dnd": {

+                "always_copy": true

+            }

+        });

+

+        $(document).off('dnd_stop.vakata', requestToHelpDrop);

+        $(document).on('dnd_stop.vakata', requestToHelpDrop);

+

+        v_helpTree.bind("hover_node.jstree", function(e, data) {

+            $("#"+data.node.id).prop("title", data.node.data);

+        });

+    }

+

+    function createRequestJSTree(p_data, p_callback) {

+        v_requestTree.jstree("destroy");

+        v_requestTree = v_requestTree.jstree({

+            "core": {

+                "data": p_data,

+                "check_callback": function(operation, node, node_parent, node_position, more) {

+                    if (operation === "copy_node" && v_checkDisabled && jsTreeUtils.isNodeFromTree(node, v_helpTree) && jsTreeUtils.getDepth(node, v_helpTree) > 1 && $("#RequestConsole_RequestTree > ul").children().length > 0) {

+                        return true;

+                    } else if (operation === "copy_node" && jsTreeUtils.isNodeFromTree(node, v_helpTree) && $("#RequestConsole_RequestTree > ul").children().length > 0) {

+                        return dragFromHelpValidate(node.id, node_parent.id);

+                    } else if (operation === "copy_node" && jsTreeUtils.isNodeFromTree(node, v_requestTree)) {

+                        return dragFromRequestValidate(node.id, node_parent.id);

+                    } else if (operation === "copy_node" && node.text === "Selection connections" && node_parent.id != "#") {

+                        return true;

+                    } else if (operation === "copy_node" && node.text === "Request connection" && node_parent.id != "#") {

+                        return true;

+                    } else if (operation === "copy_node") {

+                        return false;

+                    } else {

+                        return true;

+                    }

+                },

+                "multiple": false,

+                "animation": false,

+                "worker": false

+            },

+            "plugins": ["contextmenu", "dnd"],

+            "dnd": {

+                "always_copy": true

+            },

+            "contextmenu": {

+                "items": function($node) {

+                    return {

+                        "Edit": {

+                            "label": "Edit request",

+                            "action": function(data) {

+                                var offset = data.reference.offset();

+                                offset.left += data.reference.width();

+

+                                v_elementEditor.open(jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.reference)).path, offset);

+                                v_parent.setFocusedObj(v_elementEditor);

+                            }

+                        },

+                        "EditFilter": {

+                            "label": "Edit filter",

+                            "action": function(data) {

+                                var offset = data.reference.offset();

+                                offset.left += data.reference.width();

+

+                                var node = v_requestTree.jstree("get_node", data.reference);

+                                v_filterEditor.open(jsTreeUtils.getPath(node).path, offset);

+                                v_parent.setFocusedObj(v_filterEditor);

+                            },

+                            "separator_after": true

+                        },

+                        "Add": {

+                            "label": "Add child request",

+                            "action": function(data) {

+                                var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.reference)).path;

+                                v_viewModel.addEmptyChildRequest(mcopy(path), 0, partialRefresh);

+                                path.push(0);

+                                var added = jsTreeUtils.getLastNodeIdFromPath(v_requestTree, path);

+                                v_requestTree.jstree("deselect_node", data.reference)

+                                v_requestTree.jstree("select_node", added);

+

+                                var offset = $("#" + added + "_anchor").offset();

+                                offset.left += $("#" + added + "_anchor").width();

+

+                                v_elementEditor.open(path, offset);

+                                v_parent.setFocusedObj(v_elementEditor);

+                            }

+                        },

+                        "Copy": {

+                            "label": "Copy",

+                            "action": function(data) {

+                                var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.reference)).path;

+                                v_viewModel.copyRequest(mcopy(path), partialRefresh);

+                                path[path.length - 1] += 1;

+                                var added = jsTreeUtils.getLastNodeIdFromPath(v_requestTree, path);

+                                v_requestTree.jstree("deselect_node", data.reference)

+                                v_requestTree.jstree("select_node", added);

+                            }

+                        },

+                        "Delete": {

+                            "label": "Delete",

+                            "action": function(data) {

+                                deleteNode(data.reference);

+                            },

+                            "separator_after": true

+                        },

+                        "SizeOf": {

+                            "label": "Convert to sizeOf",

+                            "action": function(data) {

+                                var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.reference)).path;

+                                v_viewModel.convertToSizeOf(path, v_this.requestRenamed);

+                            }

+                        },

+                        "SetData": {

+                            "label": "Convert to setData or getData",

+                            "action": function(data) {

+                                var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.reference)).path;

+                                v_viewModel.convertToSetData(path, v_this.requestRenamed);

+                            }

+                        },

+                        "ElementPresent": {

+                            "label": "Convert to dataElementPresent",

+                            "action": function(data) {

+                                var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.reference)).path;

+                                v_viewModel.convertToDataElementPresent(path, v_this.requestRenamed);

+                            },

+                            "separator_after": true

+                        },

+                        "ExpandAll": {

+                            "label": "Expand all",

+                            "action": function(data) {

+                                v_requestTree.jstree("open_all");

+                            }

+                        },

+                        "CollapseAll": {

+                            "label": "Collapse all",

+                            "action": function(data) {

+                                v_requestTree.jstree("close_all");

+                            },

+                            "separator_after": true

+                        },

+                        "CopyRequestAsText": {

+                            "label": "Copy Request as Text",

+                            "action": function(data) {

+                                var text = JSON.stringify(v_viewModel.getRequest(), null, 4);

+

+                                var textArea = document.createElement("textarea");

+                                textArea.style.position = 'fixed';

+                                textArea.style.top = 0;

+                                textArea.style.left = 0;

+                                textArea.style.width = '2em';

+                                textArea.style.height = '2em';

+                                textArea.style.padding = 0;

+                                textArea.style.border = 'none';

+                                textArea.style.outline = 'none';

+                                textArea.style.boxShadow = 'none';

+                                textArea.style.background = 'transparent';

+                                textArea.value = text;

+

+                                document.body.appendChild(textArea);

+                                textArea.select();

+                                document.execCommand('copy');

+                                document.body.removeChild(textArea);

+                            }

+                        }

+                    };

+                },

+                "select_node": true

+            }

+        });

+

+        v_requestTree.bind("hover_node.jstree", function(e, data) {

+            var string = JSON.stringify(v_viewModel.getRequestCopy(jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.node.id)).path), null, 4);

+            $("#"+data.node.id).prop("title", string);

+        });

+

+        v_requestTree.bind("select_node.jstree", function (e, data) {

+            closeEditors();

+            v_parent.setFocusedObj(v_this);

+        });

+

+        v_requestTree.bind("copy_node.jstree", function(e, data) {

+            if (jsTreeUtils.isNodeFromTree(data.original, v_helpTree)) {

+                helpNodeCopied(data);

+            } else if (jsTreeUtils.isNodeFromTree(data.original, v_requestTree)) {

+                requestNodeCopied(data);

+            } else if (data.original.text === "Selection connections") {

+                v_requestTree.jstree("delete_node", data.node.id);

+            } else if (data.original.text === "Request connection") {

+                v_requestTree.jstree("delete_node", data.node.id);

+            }

+        });

+

+        jsTreeUtils.openNodes(v_requestTree, v_desktopData.openRequests);

+

+        v_requestTree.bind("after_open.jstree after_close.jstree", function(e, data) {

+            v_desktopData.openRequests = jsTreeUtils.findOpenNodes(v_requestTree);

+        });

+

+        v_requestTree.bind("after_open.jstree delete_node.jstree ready.jstree", function(e, data) {

+            // some operations are async and even their callback gets called too soon... so we have to use a timeout

+            // after_open, when we open a node, or when we insert one, delete_node, when we delete a node, and ready when the tree gets drawn in the beginning

+            setTimeout(function() {

+                v_viewModel.findSelectionsAndFilters();

+            }, 100);

+        });

+

+        v_requestTree.bind("ready.jstree", function(e, data) {

+            p_callback(true);

+        });

+

+        $(document).off('dnd_move.vakata', helpToRequestDrag);

+        $(document).on('dnd_move.vakata', helpToRequestDrag);

+

+        $(document).off('dnd_stop.vakata', helpToRequestDrop);

+        $(document).on('dnd_stop.vakata', helpToRequestDrop);

+    }

+

+    function helpToRequestDrag(event, data) {

+        var node = {

+            "id": data.data.nodes[0]

+        }

+        if ($(data.event.target).attr("id") == "RequestConsole_RequestTree" && jsTreeUtils.isNodeFromTree(node, v_helpTree) && (v_checkDisabled || dragFromHelpValidate(data.data.nodes[0], "#"))) {

+            data.helper.find('.jstree-icon').removeClass('jstree-er').addClass('jstree-ok');

+        }

+    }

+

+    function helpToRequestDrop(event, data) {

+        var node = {

+            "id": data.data.nodes[0]

+        }

+        if ($(data.event.target).attr("id") == "RequestConsole_RequestTree" && jsTreeUtils.isNodeFromTree(node, v_helpTree) && (v_checkDisabled || dragFromHelpValidate(data.data.nodes[0], "#"))) {

+            var helpPath = jsTreeUtils.getPath(v_helpTree.jstree("get_node", node.id)).path;

+            var position = $("#RequestConsole_RequestTree > ul").children().length;

+            v_viewModel.createRequest(helpPath, position, partialRefresh);

+            v_viewModel.findSelectionsAndFilters();

+        }

+    }

+

+    function requestToHelpDrop(event, data) {

+        var node = {

+            "id": data.data.nodes[0]

+        }

+        if (($(data.event.target).attr("id") == "RequestConsole_HelpTree" || jsTreeUtils.isNodeFromTree({"id": $(data.event.target).attr("id")}, v_helpTree)) && jsTreeUtils.isNodeFromTree({"id": data.data.nodes[0]}, v_requestTree)) {

+            deleteNode(v_requestTree.jstree("get_node", node.id));

+        }

+    }

+

+    function setupCallbacks() {

+        $("#RequestConsole_HelpSearch").on("input", function() {

+            v_helpTree.jstree("search", $(this).val());

+        });

+        $("#RequestConsole_Button_AddRequest").on("click", addEmptyRequest);

+

+        $("#RequestConsole_SortHelpTree").button().click(function(event, ui) {

+            if($(this).prop('checked')) {

+                v_viewModel.getHelp(createHelpJSTree, true, "WebApplications/RequestConsole/Res/getData.png");

+                v_desktopData["sortHelp"] = true;

+            } else {

+                v_viewModel.getHelp(createHelpJSTree, false, "WebApplications/RequestConsole/Res/getData.png");

+                v_desktopData["sortHelp"] = false;

+            }

+        });

+

+        if (v_desktopData["sortHelp"]) {

+            $("#RequestConsole_SortHelpTree").prev().addClass('ui-state-active');

+            $("#RequestConsole_SortHelpTree").prop('checked', true);

+        }

+    }

+

+    function partialRefresh(p_path, p_data) {

+        var parentId = getParentNodeIdFromPath(p_path);

+        v_requestTree.jstree("create_node", parentId, p_data.text, p_path[p_path.length - 1]);

+        v_requestTree.jstree("open_node", parentId);

+    }

+

+    function closeEditors() {

+        v_elementEditor.close();

+        v_filterEditor.close();

+        v_viewModel.findSelectionsAndFilters();

+    }

+

+    ///////////////////// HANDLING EVENTS //////////////////////////////

+

+    function helpNodeCopied(data) {

+        closeEditors();

+        v_requestTree.jstree("delete_node", data.node.id);

+        var helpPath = jsTreeUtils.getPath(v_helpTree.jstree("get_node", data.original.id)).path;

+        if (data.parent === "#") {

+            v_viewModel.createRequest(helpPath, data.position, partialRefresh);

+        } else {

+            var requestPath = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.parent)).path;

+            v_viewModel.addChildRequest(helpPath, requestPath, data.position, partialRefresh);

+        }

+    }

+

+    function requestNodeCopied(data) {

+        closeEditors();

+        v_requestTree.jstree("delete_node", data.node.id);

+        var fromPathObj = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.original.id));

+        var fromPath = fromPathObj.path;

+        var fromPathStr = fromPathObj.strpath;

+        var toPath = [];

+        var toPathStr = "";

+        if (data.parent != "#") {

+            var toPathObj = jsTreeUtils.getPath(v_requestTree.jstree("get_node", data.parent));

+            toPath = toPathObj.path;

+            toPathStr = toPathObj.strpath;

+        }

+        v_viewModel.moveRequest(fromPath, toPath, data.position);

+

+        function moveComplete(node, parent, pos) {

+            toPath.push(data.position);

+            v_requestTree.jstree("open_node", parent);

+        }

+

+        v_requestTree.jstree("move_node", v_requestTree.jstree("get_node", data.original.id), v_requestTree.jstree("get_node", data.parent), data.position, moveComplete);

+    }

+

+    function dragFromHelpValidate(p_helpId, p_requestParentId) {

+        var helpPath = jsTreeUtils.getPath(v_helpTree.jstree("get_node", p_helpId)).path;

+        if (p_requestParentId === "#") {

+            return v_viewModel.isValidToCreateRequest(helpPath);

+        } else {

+            var requestPath = jsTreeUtils.getPath(v_requestTree.jstree("get_node", p_requestParentId)).path;

+            return v_viewModel.isValidToAddRequest(helpPath, requestPath);

+        }

+    }

+

+    function dragFromRequestValidate(p_fromId, p_toId) {

+        var fromPath = jsTreeUtils.getPath(v_requestTree.jstree("get_node", p_fromId)).path;

+        var toPath;

+        if (p_toId != "#") {

+            toPath = jsTreeUtils.getPath(v_requestTree.jstree("get_node", p_toId)).path;

+        } else {

+            toPath = [];

+        }

+

+        return v_viewModel.isValidToMoveRequest(fromPath, toPath);

+    }

+

+    function getParentNodeIdFromPath(p_path) {

+        if (p_path.length === 1) {

+            return "#";

+        } else {

+            var id = "#";

+            for (var i = 0; i < p_path.length - 1; ++i) {

+                id = v_requestTree.jstree("get_node", id).children[p_path[i]];

+            }

+            return id;

+        }

+    }

+

+    function addEmptyRequest() {

+        closeEditors();

+

+        v_viewModel.createEmptyRequest(0, partialRefresh);

+        v_requestTree.jstree("deselect_node", v_requestTree.jstree("get_selected"));

+        var newNodeId = jsTreeUtils.getLastNodeIdFromPath(v_requestTree, [0]);

+        v_requestTree.jstree("select_node", newNodeId);

+

+        var offset = $("#" + newNodeId + "_anchor").offset();

+        offset.left += $("#" + newNodeId + "_anchor").width();

+

+        v_elementEditor.open([0], offset);

+        v_parent.setFocusedObj(v_elementEditor);

+    }

+

+    function deleteNode(p_data) {

+        var path = jsTreeUtils.getPath(v_requestTree.jstree("get_node", p_data)).path;

+        v_viewModel.deleteRequest(mcopy(path));

+

+        v_requestTree.jstree("delete_node", p_data);

+        closeEditors();

+

+        v_desktopData.openRequests = jsTreeUtils.findOpenNodes(v_requestTree);

+    }

+

+    function toggleValidation(event) {

+        if (event.keyCode == 17) {

+            if (event.type == "keydown") {

+                v_checkDisabled = true;

+            } else {

+                v_checkDisabled = false;

+            }

+        }

+    }

+

+    ///////////////////// CONNECTION RELATED /////////////////////

+

+    function RequestEndpoint(p_identifier) {

+        var v_identifier = p_identifier;

+

+        this.getOffset = function() {

+

+            var id = jsTreeUtils.getLastNodeIdFromPath(v_requestTree, v_identifier());

+            var htmlObj = $("#" + id + "_anchor");

+

+            var offset = htmlObj.offset();

+            offset.top += htmlObj.height() / 2;

+            offset.left += htmlObj.width()

+            return offset;

+        };

+

+        this.object = v_this;

+    }

+

+    this.getEndpoint = function(identifier) {

+        return new RequestEndpoint(identifier);

+    };

+

+    this.getConnectionInformation = function(identifier) {

+        return jsTreeUtils.getPath(v_requestTree.jstree("get_node", identifier));

+    };

+

+    this.disabled = function() {};

+}

+

+//# sourceURL=RequestConsole\Views\View_RequestEditor.js

diff --git a/htdocs/WebApplications/RequestTester/Main.js b/htdocs/WebApplications/RequestTester/Main.js
new file mode 100644
index 0000000..819ecf1
--- /dev/null
+++ b/htdocs/WebApplications/RequestTester/Main.js
@@ -0,0 +1,93 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+var WebApplications = WebApplications || [];

+

+WebApplications.push({'application': new RequestTesterApp()});

+

+function RequestTesterApp() {

+    "use strict";

+

+    var main = new WebAppBase();

+    var webAppModel;

+

+    var jsfiles = [

+        "WebApplications/RequestTester/ViewModel.js",

+        "WebApplications/RequestTester/View.js"

+    ];

+

+    var extension;

+    var viewModel;

+    var view;

+

+    this.info = function() {

+        return {

+            defaultIcon: "WebApplications/RequestTester/main_icon.png",

+            defaultName: "DsRestAPI Console"

+        };

+    };

+

+    this.load = function(p_webAppModel, p_params) {

+        webAppModel = p_webAppModel;

+

+        function setupLoaded() {

+            main.load(jsfiles, [], start, webAppModel.getFileHandler());

+        }

+

+        function customAppJsImported(ok, p_extension) {

+            extension = p_extension;

+            if (p_params.setup != undefined) {

+                webAppModel.getSetupModel().setSetupDirectory(p_params.customization + '/Setups');

+                webAppModel.getSetupModel().loadSetup(p_params.setup, setupLoaded, false, p_params.setupParams);

+            } else {

+                setupLoaded(true, webAppModel.getSetupModel().newSetup());

+            }

+        }

+

+        if (p_params.customization != undefined) {

+            new JsImportFromConfigTask(p_params.customization + '/AppConfig.json', webAppModel.getFileHandler()).taskOperation(customAppJsImported);

+        } else {

+            alert("No application specified, can't choose API")

+        }

+    };

+

+    function destroy() {

+        view.destroy();

+

+        view = undefined;

+        viewModel = undefined;

+    }

+

+    this.unload = function(webappUnloaded) {

+        main.unload(destroy);

+        webappUnloaded(true);

+    };

+

+    function start(p_callback) {

+        viewModel = new RequestTester_ViewModel(webAppModel.getFileHandler(), new DsRestAPI(extension));

+        view = new RequestTester_View(viewModel, "TSGuiFrameworkMain", "requestTesterMainView");

+

+        viewModel.setBinder({

+            "notifyChange": function() {

+                viewModel.sendRequest(view.refresh);

+            }

+        });

+

+        function callback(ok, msg) {

+            if (ok) {

+                view.applicationCreated(webAppModel.getSetupModel().getSetup().request.getData());

+            } else {

+                alert(msg);

+            }

+          if (typeof p_callback === "function") {

+            p_callback();

+          }

+        }

+

+        var taskList = new TaskList([new GenericTask(viewModel.init), new GenericTask(view.init)], callback);

+        taskList.taskOperation();

+    }

+}

+//# sourceURL=RequestTester\Main.js

diff --git a/htdocs/WebApplications/RequestTester/View.css b/htdocs/WebApplications/RequestTester/View.css
new file mode 100644
index 0000000..0971453
--- /dev/null
+++ b/htdocs/WebApplications/RequestTester/View.css
@@ -0,0 +1,14 @@
+#request, #response {

+	width:99%;

+    height:300px;

+    border:3px solid #eee;

+}

+

+TABLE {

+    width: 100%;

+    border: 0;

+}

+

+TD {

+    width: 50%;

+}

diff --git a/htdocs/WebApplications/RequestTester/View.html b/htdocs/WebApplications/RequestTester/View.html
new file mode 100644
index 0000000..74db5a8
--- /dev/null
+++ b/htdocs/WebApplications/RequestTester/View.html
@@ -0,0 +1,47 @@
+<style id="WebAppStyle" type="text/css"></style>

+<table>

+    <tr>

+        <td style="text-align: right;" colspan="2">

+            <span id="time">Time: &hellip; ms.</span>

+        </td>

+    </tr>

+    <tr>

+        <td>

+            <label for="request">Request</label>

+        </td>

+        <td>

+            <label for="response">Response</label>

+        </td>

+    </tr>

+    <tr>

+        <td>

+            <div id="request"></div>

+        </td>

+        <td>

+            <div id="response"></div>

+        </td>

+    </tr>

+    <tr>

+        <td colspan="2">

+            <button id="send">Send Request</button>

+            <button id="full">Request a Full Help</button>

+            <button id="help">Get help descriptor in JSON format</button>

+            <button id="jsonindent">Prettify Request JSON</button>

+        </td>

+    </tr>

+    <tr>

+        <td colspan="2">

+            <div id="autogui_container"></div>

+        </td>

+    </tr>

+    <tr>

+        <td colspan="2">

+            <label for="helpsearch">Search</label><input id="helpsearch"></input>

+        </td>

+    </tr>

+    <tr>

+        <td colspan="2">

+            <div id="helptree"></div>

+        </td>

+    </tr>

+</table>

diff --git a/htdocs/WebApplications/RequestTester/View.js b/htdocs/WebApplications/RequestTester/View.js
new file mode 100644
index 0000000..41b1969
--- /dev/null
+++ b/htdocs/WebApplications/RequestTester/View.js
@@ -0,0 +1,158 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function RequestTester_View(p_viewmodel, p_parentId, p_mainId) {

+    "use strict";

+    

+    var HTML = "WebApplications/RequestTester/View.html";

+    var v_parentId = p_parentId;

+    var parentDiv = document.getElementById(p_parentId);

+    var v_mainId = p_mainId;

+    

+    var v_viewmodel = p_viewmodel;

+    

+    var v_autoGuiView;

+    var v_helpTree;

+    var v_requestEditor;

+    var v_responseEditor;

+    var v_this = this;

+    

+    var EDITOROPTIONS = {

+        mode: "javascript",

+        lineNumbers: true,

+        smartIndent: true,

+        indentUnit: 4,

+        lineWrapping: true,

+        foldGutter: true,

+        gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],

+        matchBrackets: true,

+        autoCloseBrackets: true,

+        highlightSelectionMatches: true,

+        styleActiveLine: true

+    };

+    

+    this.init = function(p_callback) {

+        var mainDiv = document.createElement("div");

+        mainDiv.setAttribute("id", v_mainId);

+        parentDiv.appendChild(mainDiv);

+        

+        function htmlLoaded(ok, data) {

+            if (ok) {

+                $("#" + v_mainId).append(data);

+                v_viewmodel.loadCss("WebAppStyle", "WebApplications/RequestTester/View.css");

+

+                p_callback(true);

+            } else {

+                p_callback(false, "Error loading " + HTML);

+            }

+        }

+        

+        v_viewmodel.loadFile(HTML, htmlLoaded);

+    };

+    

+    this.destroy = function() {

+        $("#" + v_mainId).remove();

+    };

+

+    this.applicationCreated = function(request) {

+        v_autoGuiView = new CAutoGuiView(

+            [v_viewmodel.getAutoGuiViewModel()],

+            "autogui",

+            "autogui_container"

+        );

+        v_autoGuiView.applicationCreated();

+        

+        v_helpTree = $("#helptree");

+        

+        refreshHelpJSTree(v_viewmodel.getHelpTree());

+        setupCallbacks();

+        

+        v_requestEditor = CodeMirror(document.getElementById("request"), EDITOROPTIONS);

+        v_requestEditor.setValue(JSON.stringify(request, null, 4));

+        

+        v_responseEditor = CodeMirror(document.getElementById("response"), EDITOROPTIONS);

+    };

+    

+    function refreshHelpJSTree(p_data) {

+        v_helpTree.jstree("destroy");

+        v_helpTree = v_helpTree.jstree({

+            "core": {

+                "data": p_data,

+                "check_callback" : true,

+                "multiple" : false

+            },

+            "plugins" : ["search"],

+            "search" : {

+                "show_only_matches" : true

+            }

+        });

+        v_helpTree.bind("hover_node.jstree", function(e, data) {

+            $("#"+data.node.id).prop("title", data.node.data);

+        });

+    }

+    

+    function searchHelpTree() {

+        v_helpTree.jstree("search", $(this).val());

+    }

+    

+    function prettyPrintJSON() {

+        var str = indentJSON(v_requestEditor.getValue(), 4);

+        if(str) {

+            v_requestEditor.setValue(str);

+            return true;

+        } else {

+            alert("Malformed JSON!");

+            return false;

+        }

+    }

+

+    function loading() {

+        v_responseEditor.setValue("loading...");

+    }

+    

+    function sendRequest() {

+        var requestStr = indentJSON(v_requestEditor.getValue(), 4);

+        if (requestStr) {

+            loading();

+            var request = JSON.parse(v_requestEditor.getValue());

+            v_viewmodel.sendRequest(v_this.refresh, request);

+        } else {

+            alert("Malformed JSON");

+        }

+    };

+    

+    function sendFullRequest() {

+        loading();

+        

+        var request = DSHelpToRequest_full(v_viewmodel.getHelp());

+        v_viewmodel.sendRequest(v_this.refresh, request);

+    };

+    

+    function getHelp() {

+        var help = v_viewmodel.getHelp();

+        v_responseEditor.setValue(JSON.stringify(help, null, 4));

+    };

+    

+    this.refresh = function() {

+        var request = v_viewmodel.getRequest();

+        v_requestEditor.setValue(JSON.stringify(request, null, 4));

+        

+        var response = v_viewmodel.getResponse();

+        v_responseEditor.setValue(JSON.stringify(response, null, 4));

+        

+        v_autoGuiView.refresh(true);

+                

+        document.getElementById("time").innerHTML = v_viewmodel.getTime();

+    }

+

+    function setupCallbacks() {

+        $("#send").on('click', sendRequest);

+        $("#full").on('click', sendFullRequest);

+        $("#help").on('click', getHelp);

+        $('#helpsearch').on('input', searchHelpTree);

+        $('#jsonindent').on('click', prettyPrintJSON);

+    }

+}

+//# sourceURL=RequestTester\View.js

diff --git a/htdocs/WebApplications/RequestTester/ViewModel.js b/htdocs/WebApplications/RequestTester/ViewModel.js
new file mode 100644
index 0000000..faabf44
--- /dev/null
+++ b/htdocs/WebApplications/RequestTester/ViewModel.js
@@ -0,0 +1,89 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function RequestTester_ViewModel(p_fileHandler, p_DsRestAPI) {
+    "use strict";
+
+    var v_DsRestAPI = p_DsRestAPI;
+    var v_fileHandler = p_fileHandler;
+    var v_help;
+    
+    var v_request;
+    var v_response;
+    var v_time = 0;
+    
+    var dataSourceUtils = new DataSourceUtils();
+    
+    var v_autogui_ViewModel = new CViewModel_AutoGUI({
+        "getResponseElement" : function() {
+            return dataSourceUtils.expandResponse(v_response, 0, [], [], v_request);
+        },
+        "getDsRestAPI": function() {
+            return v_DsRestAPI;
+        }
+    });
+    
+    var v_this = this;
+    
+    this.init = function(p_callback) {
+        function helpArrived(ok, help) {
+            if (ok) {
+                v_help = new HelpTreeBuilder(help).getHelpTree(true);
+                p_callback(true);
+            } else {
+                p_callback(false, "Error getting help");
+            }
+        }
+        
+        v_DsRestAPI.getHelp(helpArrived);
+    };
+    
+    this.setBinder = function(p_binder) {
+        v_autogui_ViewModel.setBinder(p_binder);
+    }
+    
+    this.getAutoGuiViewModel = function() {
+        return v_autogui_ViewModel;
+    }
+    
+    this.sendRequest = function(refresh, request) {
+        if (request) {
+            v_request = request;
+        }
+        
+        function responseArrived(response) {
+            v_time = Date.now() - v_time;
+            v_response = response;
+            refresh();
+        }
+        
+        v_time = Date.now();
+        v_DsRestAPI.getList(v_request, responseArrived);
+    };
+
+    this.getHelpTree = function() {
+        return dataSourceUtils.convertHelpToTreeDataArray(v_help.sources);
+    };
+    
+    this.getHelp = function() {
+        return v_help;
+    }
+    
+    this.loadFile = v_fileHandler.loadFile;
+    this.loadCss = v_fileHandler.loadCss;
+    
+    this.getRequest = function() {
+        return v_request;
+    };
+    
+    this.getResponse = function() {
+        return v_response;
+    };
+    
+    this.getTime = function() {
+        return "Time: " + v_time + " ms.";
+    };
+}
+//# sourceURL=RequestTester\ViewModel.js
diff --git a/htdocs/WebApplications/RequestTester/configure.png b/htdocs/WebApplications/RequestTester/configure.png
new file mode 100644
index 0000000..c2fbc63
--- /dev/null
+++ b/htdocs/WebApplications/RequestTester/configure.png
Binary files differ
diff --git a/htdocs/WebApplications/RequestTester/main_icon.png b/htdocs/WebApplications/RequestTester/main_icon.png
new file mode 100644
index 0000000..15aca68
--- /dev/null
+++ b/htdocs/WebApplications/RequestTester/main_icon.png
Binary files differ
diff --git a/htdocs/WebApplications/ServerBrowser/Main.js b/htdocs/WebApplications/ServerBrowser/Main.js
new file mode 100644
index 0000000..6052147
--- /dev/null
+++ b/htdocs/WebApplications/ServerBrowser/Main.js
@@ -0,0 +1,57 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+var WebApplications = WebApplications || [];

+

+WebApplications.push({'application': new ServerBrowserApp()});

+

+function ServerBrowserApp() {

+    "use strict";

+

+    var main = new WebAppBase();

+    var webAppModel;
+    var view;
+    var viewModel;
+    

+    var jsfiles = [

+        "WebApplications/ServerBrowser/ViewModel.js",

+        "WebApplications/ServerBrowser/View.js"

+    ];

+    

+    this.info = function() {

+        return {

+            defaultIcon: "WebApplications/ServerBrowser/images/main_icon.png",

+            defaultName: "Server Browser"

+        };

+    };

+    

+    this.load = function(p_webAppModel)  {

+        webAppModel = p_webAppModel;

+        main.load(jsfiles, [], start, webAppModel.getFileHandler());

+    };

+    

+    function destroy() {

+        view.destroy();

+        viewModel.destroy();
+        

+        view = undefined;

+        viewModel = undefined;

+    }

+    

+    this.unload = function(unloadFinished) {

+        main.unload(destroy);

+        unloadFinished(true);

+    };

+    

+    function start(p_callback) {

+    viewModel = new ServerBrowser_ViewModel(webAppModel.getFileHandler());
+    view = new ServerBrowser_View(viewModel);
+    view.init(function noop(){});
+    if(p_callback)
+        p_callback();
+    view.applicationCreated();
+    }

+}

+//# sourceURL=ServerBrowser\Main.js

diff --git a/htdocs/WebApplications/ServerBrowser/View.css b/htdocs/WebApplications/ServerBrowser/View.css
new file mode 100644
index 0000000..9535b6d
--- /dev/null
+++ b/htdocs/WebApplications/ServerBrowser/View.css
@@ -0,0 +1,64 @@
+DIV {
+    margin:0;
+    padding:0;
+}
+#servercontainer {
+    width: 100%;
+}
+
+#wrapper {
+    display: -webkit-flex;
+    -webkit-justify-content: center;
+
+    display: flex;
+    justify-content: center;
+
+}
+/* flex issues? see: https://github.com/philipwalton/flexbugs */
+#wrapper > DIV {
+    -webkit-flex: 1;
+    flex: 1;
+    border:thin solid #777;
+}

+#wrapper DIV.bread {

+    border-bottom:thin solid #777;

+    margin: 10px;

+}

+#wrapper  LI {

+    list-style-type: none;

+    padding-left: 20px;

+}
+LI[filetype="-d"] {

+    background: url("/WebApplications/ServerBrowser/images/d.png") no-repeat;

+}

+LI[filetype="-f"] {

+    background: url("/WebApplications/ServerBrowser/images/f.png") no-repeat;

+}

+LI[filetype="ld"] {

+    background: url("/WebApplications/ServerBrowser/images/ld.png") no-repeat;

+}

+LI[filetype="lf"] {

+    background: url("/WebApplications/ServerBrowser/images/lf.png") no-repeat;

+}

+

+LI, LI SPAN {

+    cursor: pointer;

+}

+LI SPAN.name {

+    font-family: Consolas, "Courier New", Courier, monospace;

+}

+LI SPAN.size, LI SPAN.time {

+    font-size: 80%;

+}

+LI SPAN.size:before {

+    content: " [";

+}

+LI SPAN.size:after {

+    content: "B] ";

+}

+LI SPAN.time:before {

+    content: " @";

+}

+LI SPAN.time:after {

+    content: " ";

+}

diff --git a/htdocs/WebApplications/ServerBrowser/View.html b/htdocs/WebApplications/ServerBrowser/View.html
new file mode 100644
index 0000000..543c07e
--- /dev/null
+++ b/htdocs/WebApplications/ServerBrowser/View.html
@@ -0,0 +1,11 @@
+<style id="WebAppStyle" type="text/css"></style>
+<div id="wrapper">
+<div id="left">
+    <div class="bread" id="leftbread"></div>
+    <div class="list" id="leftlist"></div>
+</div>
+<div id="right">
+    <div class="bread" id="rightbread"></div>
+    <div class="list" id="rightlist"></div>
+</div>
+</div>
\ No newline at end of file
diff --git a/htdocs/WebApplications/ServerBrowser/View.js b/htdocs/WebApplications/ServerBrowser/View.js
new file mode 100644
index 0000000..768435b
--- /dev/null
+++ b/htdocs/WebApplications/ServerBrowser/View.js
@@ -0,0 +1,131 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function ServerBrowser_View(p_viewmodel) {

+    "use strict";

+    

+    var HTML = "WebApplications/ServerBrowser/View.html";

+    var CSS = "WebApplications/ServerBrowser/View.css";

+    var CSSNodeId = "WebAppStyle";

+    var v_mainId = "servercontainer";

+    var v_mainSelector = '#' + v_mainId;
+    

+    var v_viewmodel = p_viewmodel;

+    var v_this = this;

+    

+    this.init = function(p_callback) {

+        var mainDiv = document.createElement("div");

+        mainDiv.setAttribute("id", v_mainId);

+        $("#TSGuiFrameworkMain").append(mainDiv);

+        

+        function htmlLoaded(ok, data) {

+            if (ok) {

+                $(v_mainSelector).append(data);

+                // View's HTML fragment loaded, now go for the CSS.

+                v_viewmodel.loadCss(CSSNodeId, CSS);

+                // Load files of the root dir
+                fillPanel('/', 'leftlist');

+                fillPanel('/', 'rightlist');

+                

+                p_callback(true);

+            } else {

+                p_callback(false, "Error loading " + HTML);

+            }

+        }

+        

+        v_viewmodel.loadFile(HTML, htmlLoaded);

+    };

+    

+    this.destroy = function() {

+        $(v_mainSelector).remove();

+    };

+

+    this.applicationCreated = function(request) {

+    };

+    

+    function fillPanel(path, p_id) {

+        v_viewmodel.ls(path, function(d) {

+            var dirs = d.sort(sortLs);

+            var v_ul = document.createElement('ul');

+            var v_idSelector = '#' + p_id;

+            if (path !== "/") {

+                var v_liup = document.createElement('li');

+                v_liup.setAttribute('path', pathOneUp(path));

+                v_liup.setAttribute('filetype', "-d");

+                v_liup.innerHTML = "..";

+                v_ul.appendChild(v_liup);

+            }

+            for (var k in dirs) {

+                if (dirs.hasOwnProperty(k)) {

+                    var v_li = document.createElement('li');

+                    var v_value = dirs[k];

+                    if (v_value.fileName[0] != "/")

+                        v_value.fileName = "/" + v_value.fileName;

+                    if (v_value.fileName.endsWith("/"))

+                        v_value.fileName = v_value.fileName.slice(0, -1);

+                    var v_displayname = v_value.fileName.substr(v_value.fileName.lastIndexOf('/') + 1);

+                    v_li.setAttribute('path', v_value.fileName);

+                    v_li.setAttribute('filetype', v_value.contentType);

+                    if (v_value.contentType.endsWith("d"))

+                        v_li.innerHTML = "<span class='name'>" + v_displayname + "</span>";

+                    else if (v_value.contentType.endsWith("f"))

+                        v_li.innerHTML = "<span class='name'>" + v_displayname + "</span><span class='size'>" + v_value.size + "</span><span class='time'>" + (new Date(v_value.timestamp * 1000)).toISOString() + "</span>";

+                    else

+                        v_li.innerHTML = v_value.contentType + ": <span class='name'>" + v_displayname + "</span><span class='size'>" + v_value.size + "</span><span class='time'>" + (new Date(v_value.timestamp * 1000)).toISOString() + "</span>";

+                    v_ul.appendChild(v_li);

+                }

+            }

+            $('ul', v_idSelector).remove();

+            $(v_idSelector, v_mainSelector).siblings(".bread").text(path);

+            $(v_idSelector, v_mainSelector).append(v_ul);

+            $('ul', v_idSelector).off('click', 'li', onItemClick);

+            $('ul', v_idSelector).on('click', 'li', onItemClick);

+        });

+    }

+    

+    function onItemClick(event) {

+        var v_parentId = event.currentTarget.parentElement.parentElement.id;

+        var v_newpath = event.currentTarget.getAttribute('path');

+        var v_filetype = event.currentTarget.getAttribute('filetype');

+        if (v_filetype.endsWith("d")) {

+            fillPanel(v_newpath, v_parentId);

+        } else {

+            download(v_newpath.substr(v_newpath.lastIndexOf("/")+1), v_newpath);

+        }

+        return false;

+    }

+    

+    function sortLs(a, b) {

+        var isDirA = (a.contentType.endsWith("d")), isDirB = (b.contentType.endsWith("d"));

+        // Directories first.

+        if (isDirA && !isDirB) {

+            return -1;

+        } else if (isDirB && !isDirA) {

+            return 1;

+        } else {

+            return a.fileName.localeCompare(b.fileName);

+        }

+    }

+    

+    function pathOneUp(path) {

+        if (path.slice(-1) == "/")

+            path = path.slice(0, -1);

+        return path.substr(0, path.lastIndexOf("/") + 1);

+    }

+    

+    function download(filename, path) {

+        var element = document.createElement('a');

+        element.setAttribute('href', path);

+        element.setAttribute('download', filename);

+

+        element.style.display = 'none';

+        document.body.appendChild(element);

+

+        element.click();

+

+        document.body.removeChild(element);

+    }
+}

+//# sourceURL=ServerBrowser\View.js

diff --git a/htdocs/WebApplications/ServerBrowser/ViewModel.js b/htdocs/WebApplications/ServerBrowser/ViewModel.js
new file mode 100644
index 0000000..a9891ec
--- /dev/null
+++ b/htdocs/WebApplications/ServerBrowser/ViewModel.js
@@ -0,0 +1,22 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function ServerBrowser_ViewModel(p_fileHandler) {
+    "use strict";
+
+    var v_fileHandler = p_fileHandler;
+
+    this.init = function(p_callback) {
+        p_callback(true);
+    };
+
+    this.destroy = function() {};
+
+    this.loadFile = v_fileHandler.loadFile;
+    this.loadCss = v_fileHandler.loadCss;
+
+    this.ls = v_fileHandler.getDirectory;
+}
+//# sourceURL=ServerBrowser\ViewModel.js
diff --git a/htdocs/WebApplications/ServerBrowser/images/d.png b/htdocs/WebApplications/ServerBrowser/images/d.png
new file mode 100644
index 0000000..a8be6e3
--- /dev/null
+++ b/htdocs/WebApplications/ServerBrowser/images/d.png
Binary files differ
diff --git a/htdocs/WebApplications/ServerBrowser/images/f.png b/htdocs/WebApplications/ServerBrowser/images/f.png
new file mode 100644
index 0000000..3ff2334
--- /dev/null
+++ b/htdocs/WebApplications/ServerBrowser/images/f.png
Binary files differ
diff --git a/htdocs/WebApplications/ServerBrowser/images/ld.png b/htdocs/WebApplications/ServerBrowser/images/ld.png
new file mode 100644
index 0000000..b429d9c
--- /dev/null
+++ b/htdocs/WebApplications/ServerBrowser/images/ld.png
Binary files differ
diff --git a/htdocs/WebApplications/ServerBrowser/images/lf.png b/htdocs/WebApplications/ServerBrowser/images/lf.png
new file mode 100644
index 0000000..1a2811a
--- /dev/null
+++ b/htdocs/WebApplications/ServerBrowser/images/lf.png
Binary files differ
diff --git a/htdocs/WebApplications/ServerBrowser/images/main_icon.png b/htdocs/WebApplications/ServerBrowser/images/main_icon.png
new file mode 100644
index 0000000..87d882f
--- /dev/null
+++ b/htdocs/WebApplications/ServerBrowser/images/main_icon.png
Binary files differ
diff --git a/htdocs/WebApplications/TitansimConfiguration/Main.js b/htdocs/WebApplications/TitansimConfiguration/Main.js
new file mode 100644
index 0000000..5243949
--- /dev/null
+++ b/htdocs/WebApplications/TitansimConfiguration/Main.js
@@ -0,0 +1,61 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+var WebApplications = WebApplications || [];

+

+WebApplications.push({'application': new TitansimConfigurationApp()});

+

+function TitansimConfigurationApp() {

+    "use strict";

+    var main = new WebAppBase();

+    var webAppModel;

+    

+    var jsfiles = [

+        "WebApplications/TitansimConfiguration/ViewModel.js",

+        "WebApplications/TitansimConfiguration/View.js"

+    ];

+    

+    this.info = function() {

+        return {

+            defaultIcon: "WebApplications/TitansimConfiguration/main_icon.png",

+            defaultName: "Titansim Configuration"

+        };

+    };

+    

+    this.load = function(p_webAppModel) {

+        webAppModel = p_webAppModel;

+        main.load(jsfiles, [], start, webAppModel.getFileHandler());

+    };

+    

+    function destroy() {

+        $("#ConfigEditor_MainView").remove();

+    }

+

+    this.unload = function(webappUnloaded) {

+        main.unload(destroy);

+        webappUnloaded(true);

+    };

+    

+    function start(p_callback) {

+        var viewmodel = new TitansimConfiguration_ViewModel(webAppModel.getFileHandler());

+        var view = new TitansimConfiguration_View(viewmodel, "TSGuiFrameworkMain", "ConfigEditor_MainView");

+        

+        function initDone(ok, msg) {

+            if (ok) {

+                view.applicationCreated();

+            } else {

+                alert("Initializing config editor failed");

+            }

+            

+            if (typeof p_callback === "function") {

+                p_callback();

+            }

+        }

+        

+        view.init(initDone);

+    }

+}

+

+//# sourceURL=TitansimConfiguration\Main.js

diff --git a/htdocs/WebApplications/TitansimConfiguration/View.css b/htdocs/WebApplications/TitansimConfiguration/View.css
new file mode 100644
index 0000000..7481dd8
--- /dev/null
+++ b/htdocs/WebApplications/TitansimConfiguration/View.css
@@ -0,0 +1,15 @@
+#TitansimConfiguration_Title {
+    font-size: 20px;
+    font-weight: bold;
+}
+
+#TitansimConfiguration_ButtonBar {
+    border-bottom: thin solid #777;
+    border-top: thin solid #777;
+    padding: 4px;
+    margin: 10px
+}
+
+#TitansimConfiguration_ButtonBar BUTTON {
+    display: inline-block;
+}
\ No newline at end of file
diff --git a/htdocs/WebApplications/TitansimConfiguration/View.html b/htdocs/WebApplications/TitansimConfiguration/View.html
new file mode 100644
index 0000000..361586c
--- /dev/null
+++ b/htdocs/WebApplications/TitansimConfiguration/View.html
@@ -0,0 +1,9 @@
+<style id="TitansimConfiguration_WebAppStyle" type="text/css"></style>
+<style id="TitansimConfiguration_FileSelectorStyle" type="text/css"></style>
+<div id="TitansimConfiguration_Title">Currently editing:</div>
+<div id="TitansimConfiguration_ButtonBar">
+    <button id="TitansimConfiguration_Load">Load</button>
+    <button id="TitansimConfiguration_Save">Save</button>
+    <button id="TitansimConfiguration_Restart">Restart</button>
+</div>
+<div id="TitansimConfiguration_Editor"></div>
\ No newline at end of file
diff --git a/htdocs/WebApplications/TitansimConfiguration/View.js b/htdocs/WebApplications/TitansimConfiguration/View.js
new file mode 100644
index 0000000..92835a3
--- /dev/null
+++ b/htdocs/WebApplications/TitansimConfiguration/View.js
@@ -0,0 +1,110 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function TitansimConfiguration_View(p_viewmodel, p_parentId, p_mainId) {
+    "use strict";
+
+    var EDITOROPTIONS = {
+        mode: "javascript",
+        lineNumbers: true,
+        smartIndent: true,
+        indentUnit: 4,
+        lineWrapping: true,
+        foldGutter: true,
+        gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
+        matchBrackets: true,
+        autoCloseBrackets: true,
+        highlightSelectionMatches: true,
+        styleActiveLine: true
+    };
+
+    var HTML = "WebApplications/TitansimConfiguration/View.html";
+
+    var v_parentId = p_parentId;
+    var v_mainId = p_mainId;
+
+    var v_viewmodel = p_viewmodel;
+    var v_editor;
+    var v_this = this;
+
+    this.init = function(p_callback) {
+        var mainDiv = document.createElement("div");
+        mainDiv.setAttribute("id", v_mainId);
+        $("#" + v_parentId).append(mainDiv);
+
+        function htmlLoaded(ok, data) {
+            if (ok) {
+                $('#' + v_mainId).append(data);
+                v_viewmodel.loadCss("TitansimConfiguration_WebAppStyle", "WebApplications/TitansimConfiguration/View.css");
+                $("#TitansimConfiguration_Save").prop("disabled", "false");
+                v_editor = CodeMirror(document.getElementById("TitansimConfiguration_Editor"), EDITOROPTIONS);
+                v_editor.setSize("100%", "100%");
+
+                p_callback(true);
+            } else {
+                p_callback(false, "Error loading " + HTML);
+            }
+        }
+
+        v_viewmodel.loadFile(HTML, htmlLoaded);
+    };
+
+    this.applicationCreated = function() {
+        setupCallbacks();
+    };
+
+    function refresh(ok, data) {
+        if (ok) {
+            v_editor.setValue(data);
+            $("#TitansimConfiguration_Save").prop("disabled", false);
+        } else {
+            v_editor.setValue("");
+            alert("Failed to load file");
+            $("#TitansimConfiguration_Save").prop("disabled", true);
+            $("#TitansimConfiguration_Title").html("Currently editing:");
+        }
+    }
+
+    function load() {
+        function fileSelected(selected) {
+            $("#TitansimConfiguration_Title").html("Currently editing: " + selected[0].text);
+            v_viewmodel.load(selected[0].value, refresh);
+        }
+
+        var dialog = FileDialog(v_viewmodel.getFileHandler(), v_mainId, v_mainId + "_LoadFile", {
+            "header": "Select a file to load",
+            "text": "Please select a file to load",
+            "fileTypeList": ["*.cfg"],
+            "callback": fileSelected
+        });
+
+        dialog.open();
+    }
+
+    function save() {
+        v_viewmodel.save(v_editor.getValue());
+    }
+
+    function restart() {
+        var div = document.createElement("div");
+        div.setAttribute("class", "ui-widget-overlay ui-front");
+        div.setAttribute("style", "z-index: 100;");
+        $("#" + v_parentId).append(div);
+
+        function callback() {
+            $(div).remove();
+        }
+
+        v_viewmodel.restart(callback);
+    }
+
+    function setupCallbacks() {
+        $("#TitansimConfiguration_Load").click(load);
+        $("#TitansimConfiguration_Save").click(save);
+        $("#TitansimConfiguration_Restart").click(restart);
+    }
+
+}
+//# sourceURL=TitansimConfiguration\View.js
diff --git a/htdocs/WebApplications/TitansimConfiguration/ViewModel.js b/htdocs/WebApplications/TitansimConfiguration/ViewModel.js
new file mode 100644
index 0000000..604094a
--- /dev/null
+++ b/htdocs/WebApplications/TitansimConfiguration/ViewModel.js
@@ -0,0 +1,54 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+function TitansimConfiguration_ViewModel(p_fileHandler) {
+    "use strict";
+
+    var v_fileHandler = p_fileHandler;
+    var v_loader;
+
+    this.loadFile = v_fileHandler.loadFile;
+    this.loadCss = v_fileHandler.loadCss;
+    
+    this.load = function(url, refresh) {
+        v_loader = new FileLoader(url, v_fileHandler);
+        v_loader.taskOperation(refresh);
+    }
+    
+    this.save = function(data) {
+        v_loader.setData(data);
+        v_loader.save();
+    };
+    
+    this.restart = function(callback) {
+        v_fileHandler.setData(function() {}, "ExecCtrl", "Restart", "0", 0);
+        
+        function checkOffline() {
+            ping(false, callback);
+        }
+        setTimeout(function() {
+            ping(callback);
+        }, 10000);
+    };
+    
+    function ping(callback) {
+        function gotAnswer(ans) {
+            if (ans) {
+                callback();
+            } else {
+                setTimeout(function() {
+                    ping(callback);
+                }, 1000);
+            }
+        }
+        
+        v_fileHandler.loadFile("Main.html", gotAnswer);
+    }
+    
+    this.getFileHandler = function() {
+        return v_fileHandler;
+    };
+}
+//# sourceURL=TitansimConfiguration\ViewModel.js
diff --git a/htdocs/WebApplications/TitansimConfiguration/main_icon.png b/htdocs/WebApplications/TitansimConfiguration/main_icon.png
new file mode 100644
index 0000000..c0ec1ae
--- /dev/null
+++ b/htdocs/WebApplications/TitansimConfiguration/main_icon.png
Binary files differ
diff --git a/htdocs/WebApplications/WebpageFrame/Main.js b/htdocs/WebApplications/WebpageFrame/Main.js
new file mode 100644
index 0000000..54760b5
--- /dev/null
+++ b/htdocs/WebApplications/WebpageFrame/Main.js
@@ -0,0 +1,61 @@
+// Copyright (c) 2000-2017 Ericsson Telecom AB                                                       //
+// All rights reserved. This program and the accompanying materials are made available under the     //
+// terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at //
+// http://www.eclipse.org/legal/epl-v10.html                                                         //
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+var WebApplications = WebApplications || [];
+
+WebApplications.push({"application": new WebpageFrame_Application()});
+
+function WebpageFrame_Application() {
+
+    var v_appBase = new WebAppBase();
+    var v_location;
+    var v_sendCredentials = false;
+
+    this.info = function() {
+        return {
+            defaultIcon: "WebApplicationFramework/Res/help.png",
+            defaultName: "WebpageFrame"
+        };
+    };
+
+    this.load = function(p_webAppModel, p_params, p_framework)  {
+        v_location = p_params.location;
+        v_sendCredentials = p_params.sendCredentials;
+        v_appBase.load([], [], start, p_webAppModel.getFileHandler());
+    };
+
+    this.unload = function(webappUnloaded) {
+        v_appBase.unload(destroy);
+        webappUnloaded(true);
+    };
+
+    function onWindowResize(event) {
+        if (event.target == window) {
+            $("#WebpageFrame").height(ViewUtils.getSuggestedHeight("WebpageFrame"));
+        }
+    }
+
+    function start(callback) {
+        if (v_location != undefined) {
+            var html = '<iframe src="' + v_location + '" id="WebpageFrame" width="100%"></iframe>';
+            $("#TSGuiFrameworkMain").append(html);
+
+            $(window).on("resize", onWindowResize);
+            $("#WebpageFrame").height(ViewUtils.getSuggestedHeight("WebpageFrame"));
+
+            if (v_sendCredentials) {
+                $("#WebpageFrame").load(function() {
+                    this.contentWindow.postMessage({'username': localStorage.username, 'password': localStorage.password}, '*');
+                });
+            }
+        }
+        callback(true);
+    }
+
+    function destroy() {
+        $(window).off("resize", onWindowResize);
+        $("#WebpageFrame").remove();
+    }
+}
\ No newline at end of file
diff --git a/htdocs/favicon.ico b/htdocs/favicon.ico
new file mode 100644
index 0000000..88090fd
--- /dev/null
+++ b/htdocs/favicon.ico
Binary files differ
diff --git a/htdocs/index.html b/htdocs/index.html
new file mode 100644
index 0000000..56966c4
--- /dev/null
+++ b/htdocs/index.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<!--Copyright (c) 2000-2017 Ericsson Telecom AB
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+which accompanies this distribution, and is available at
+http:www.eclipse.org/legal/epl-v10.html                           --> 
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+        <meta charset="UTF-8">
+
+        <!-- CSS -->
+        <link rel="stylesheet" type="text/css" href="WebApplicationFramework/Res/Main.css" />
+        <!--link rel="stylesheet" type="text/css" href="Libs/JQueryUI/themes/cupertino/jquery-ui.min.css" /-->
+        <link rel="stylesheet" type="text/css" href="Libs/JQueryUI/jquery-ui.css" />
+        <!--link rel="stylesheet" type="text/css" href="Libs/JQueryUI/jquery-ui.structure.css" /-->
+        <!--link rel="stylesheet" type="text/css" href="Libs/JQueryUI/jquery-ui.theme.css" /-->
+        <link rel="stylesheet" type="text/css" href="Libs/jsTree/themes/default/style.min.css" />
+        <link rel="stylesheet" type="text/css" href="Libs/Codemirror/codemirror.css" />
+
+        <!-- GENERAL LIBS -->
+        <script src="Utils/Polyfill.js"></script>
+        <script src="Utils/Compat.js"></script>
+        <!-- Polyfill the Zeroth, for the old browsers. -->
+        <script src="Libs/JQuery/jquery-2.2.3.min.js"></script>
+        <script src="Libs/JQuery/jquery.svg.js"></script>
+        <script src="Libs/jsTree/jstree.min.js"></script>
+        <script src="Libs/JQueryUI/jquery-ui.js "></script>
+        <script src="Libs/AJV/ajv.min.js"></script>
+        <script src="Libs/Html2Canvas/html2canvas.js"></script>
+        <script src="Libs/Flot/jquery.flot.min.js"></script>
+        <script src="Libs/Flot/jquery.flot.time.js"></script>
+        <script src="Libs/Flot/jquery.flot.resize.min.js"></script>
+        <script src="Libs/Flot/jquery.flot.navigate.min.js"></script>
+        <!-- Customized libs -->
+        <script src="Libs/JSONEditor/jsoneditor.custom.js"></script>
+        <script src="Libs/Codemirror/codemirror.custom.js"></script>
+
+        <!-- GENERAL UTILITIES -->
+        <script src="Utils/Utilities.js"></script>
+        <script src="Utils/LineDrawer.js"></script>
+        <script src="Utils/FileHandler.js"></script>
+        <script src="Utils/TaskUtils.js"></script>
+        <script src="Utils/JsonLoader.js"></script>
+        <script src="Utils/FileLoader.js"></script>
+        <script src="Utils/DataSourceUtils.js"></script>
+        <script src="Utils/JsTreeUtils.js"></script>
+        <script src="Utils/ViewUtils.js"></script>
+        <script src="Utils/RequestBuilderFromHelp_full.js"></script>
+        <script src="Utils/RequestBuilderFromHelp_manual.js"></script>
+        <script src="Utils/HelpTreeBuilder.js"></script>
+
+        <!-- MAIN SCRIPTS -->
+        <script src="WebApplicationFramework/FrameworkMain.js"></script>
+        <script src="WebApplicationFramework/Setup_Model.js"></script>
+        <script src="WebApplicationFramework/WebApp_Model.js"></script>
+
+        <title>TitanSim RnXnn</title>
+    </head>
+    <body>
+        <div id="TSGuiFrameworkMain">
+            <div id="applications_header_container">
+                <!--div class="line"></div-->
+                <div id="applications_header" class="applications_header_class">
+                    <!-- toggle for hidden applications, connected code can also be found in FrameworkMain.js and Main.css -->
+                    <!--div id="webappToggle"><button id="webappToggleButton"><span><img src="WebApplicationFramework/Res/grip_gray.png"/></span></button></div>
+                    <div id="hiddenWebapps" class="hidden"></div-->
+                    <div id="webapps"></div>
+                    <div id="eriHdr"><span><img class="margin_logo" src="WebApplicationFramework/Res/ericsson.png"/>TitanSim RnXnn</span></div>
+                </div>
+                <div class="line"></div>
+            </div>
+        </div>
+    </body>
+</html>
diff --git a/license.txt b/license.txt
new file mode 100644
index 0000000..c29ecb0
--- /dev/null
+++ b/license.txt
@@ -0,0 +1,13 @@
+Copyright (c) 2000-2017 Ericsson Telecom AB

+

+All rights reserved. 

+

+This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at http:www.eclipse.org/legal/epl-v10.html

+

+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

+

+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

+Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

+

+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/project/placeholder b/project/placeholder
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/placeholder